Identity — OTP / 2FA

Le module OTP implémente l’authentification multi-facteurs avec trois canaux : email, TOTP (RFC 6238), et codes de récupération statiques.

Module : src.module.identity.domain.otp_service

OTP par Email

src.module.identity.domain.otp_service.generate_email_otp(user, device) str

Génère un code OTP à 6 chiffres et l’envoie par email.

  1. Crée un OTPChallenge avec TTL configurable (OTP_EMAIL_TOKEN_VALIDITY_SECONDS)

  2. Envoie l’email avec le code

  3. Retourne le code (pour les tests)

Parameters:
  • user – Utilisateur cible

  • device – OTPDevice de type "email"

Returns:

Code OTP généré

src.module.identity.domain.otp_service.verify_email_otp(device, code: str) bool

Vérifie un code OTP email.

  • Cherche un OTPChallenge non utilisé et non expiré

  • Marque le challenge comme utilisé

  • Retourne True si le code est valide

Parameters:
  • device – OTPDevice de type "email"

  • code – Code à vérifier

Returns:

True si valide

TOTP (Time-based One-Time Password)

Implémentation conforme à la RFC 6238 utilisant HMAC-SHA1 avec des pas de 30 secondes.

src.module.identity.domain.otp_service.setup_totp(user) tuple[OTPDevice, str]

Initialise un dispositif TOTP.

  1. Génère un secret aléatoire base32

  2. Crée un OTPDevice non confirmé

  3. Retourne le dispositif et l’URI otpauth:// pour les QR codes

Returns:

Tuple (device, provisioning_uri)

device, uri = setup_totp(user)
# uri = "otpauth://totp/updo:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=updo"
# Afficher comme QR code pour Google Authenticator / Authy
src.module.identity.domain.otp_service.confirm_totp(device, code: str) bool

Confirme un dispositif TOTP en vérifiant le premier code.

  • Vérifie le code TOTP contre le secret stocké

  • Si valide, marque le dispositif comme is_confirmed=True

  • Émet OTPDeviceConfirmed

Parameters:
  • device – OTPDevice TOTP non confirmé

  • code – Code TOTP à 6 chiffres

Returns:

True si confirmé avec succès

src.module.identity.domain.otp_service.verify_totp(device, code: str) bool[source]

Vérifie un code TOTP.

Accepte le code courant et les codes des fenêtres adjacentes (±1 pas) pour compenser le décalage d’horloge.

Parameters:
  • device – OTPDevice TOTP confirmé

  • code – Code TOTP à 6 chiffres

Returns:

True si valide

Codes de récupération statiques

src.module.identity.domain.otp_service.generate_static_codes(user, count: int = 10) list[str][source]

Génère un ensemble de codes de récupération à usage unique.

Parameters:
  • user – Utilisateur cible

  • count – Nombre de codes (défaut: OTP_STATIC_TOKEN_COUNT)

Returns:

Liste de codes alphanumériques

codes = generate_static_codes(user)
# ['ABC12345', 'DEF67890', 'GHI24680', ...]
# L'utilisateur doit les sauvegarder en lieu sûr
src.module.identity.domain.otp_service.verify_static_code(device, code: str) bool[source]

Vérifie et consomme un code de récupération.

  • Cherche le code dans la liste stockée

  • Le supprime de la liste (usage unique)

  • Retourne True si trouvé

Parameters:
  • device – OTPDevice de type "static"

  • code – Code de récupération

Returns:

True si valide et consommé

Fonction unifiée

src.module.identity.domain.otp_service.verify_otp(user, code: str, device_type: str | None = None) bool[source]

Point d’entrée unifié pour la vérification OTP.

Essaie les dispositifs actifs dans l’ordre :

  1. TOTP (si device_type est None ou "totp")

  2. Email (si device_type est None ou "email")

  3. Static (si device_type est None ou "static")

Parameters:
  • user – Utilisateur

  • code – Code OTP

  • device_type – Type spécifique à vérifier (optionnel)

Returns:

True si un dispositif valide le code

Endpoints API

POST /api/v1/auth/otp/totp/setup/       → Initialise TOTP, retourne URI + secret
POST /api/v1/auth/otp/totp/confirm/      → Confirme le dispositif TOTP
POST /api/v1/auth/otp/email/send/        → Envoie un code OTP par email
POST /api/v1/auth/otp/static/generate/   → Génère des codes de récupération
POST /api/v1/auth/otp/verify/            → Vérifie un code OTP (tous types)
GET  /api/v1/auth/otp/devices/           → Liste les dispositifs OTP
DELETE /api/v1/auth/otp/devices/<id>/     → Supprime un dispositif

Configuration

MULTITENANT = {
    'OTP_ENABLED': True,
    'OTP_EMAIL_ENABLED': True,
    'OTP_TOTP_ENABLED': True,
    'OTP_STATIC_ENABLED': True,
    'OTP_EMAIL_TOKEN_VALIDITY_SECONDS': 300,  # 5 minutes
    'OTP_TOTP_ISSUER_NAME': 'updo',
    'OTP_STATIC_TOKEN_COUNT': 10,
    'OTP_REQUIRED_FOR_LOGIN': False,
}