Expression de Besoin — PD-238¶
Endpoints de gestion MFA utilisateur¶
1. Contexte¶
ProbatioVault dispose d'un système de validation MFA délégué à l'IdP Keycloak (PD-27), qui vérifie si un utilisateur est authentifié avec MFA via les claims OIDC (amr, acr). Cependant, aucun endpoint ne permet à un utilisateur de gérer ses paramètres MFA (activer/désactiver TOTP, consulter l'état MFA, gérer les codes de récupération).
PD-238 couvre uniquement les endpoints de gestion MFA. Les endpoints de changement de mot de passe, suppression de compte et logout relèvent d'autres user stories.
Relation avec PD-106 (consommateur principal)¶
L'application mobile iOS PD-106 (Écran Settings iOS) est le principal consommateur de PD-238. PD-106 a été spécifiée avec l'hypothèse que des endpoints backend de gestion MFA existent :
| Endpoint attendu par PD-106 | Fonction |
|---|---|
GET /user/mfa/status | État MFA (actif/inactif, méthode) |
POST /user/mfa/totp/init | Initialisation TOTP (QR code, secret) |
POST /user/mfa/totp/verify | Vérification du code TOTP initial |
POST /user/mfa/disable | Désactivation MFA |
POST /user/mfa/recovery/regenerate | Régénération des codes de récupération |
POST /auth/reauth | Re-authentification pour opérations sensibles |
PD-106 est bloquée sur sa partie MFA tant que PD-238 n'est pas implémentée. La partie profil de PD-106 peut avancer car elle consomme PD-32 (déjà implémenté).
Relation avec PD-27¶
PD-27 définit la validation MFA (vérifier qu'un utilisateur est authentifié MFA). PD-238 définit la gestion MFA (permettre à l'utilisateur de configurer son MFA). Ces deux stories sont complémentaires : - PD-27 : "L'utilisateur est-il authentifié MFA ?" (middleware de validation) - PD-238 : "L'utilisateur peut-il activer/désactiver son MFA ?" (endpoints de configuration)
Intégration Keycloak¶
Les endpoints PD-238 délèguent la gestion MFA à Keycloak via son Admin REST API. Le backend ProbatioVault agit comme proxy avec un service account admin pour : - Récupérer l'état MFA d'un utilisateur - Initialiser la configuration TOTP - Valider le code TOTP initial - Désactiver le MFA - Gérer les codes de récupération (15 codes par défaut Keycloak)
2. Objectifs principaux¶
- Permettre à un utilisateur authentifié de consulter son état MFA (actif/inactif, méthode configurée).
- Permettre à un utilisateur d'activer le MFA TOTP via un flux sécurisé (secret + QR code + vérification).
- Permettre à un utilisateur de désactiver son MFA avec re-authentification obligatoire.
- Permettre à un utilisateur de régénérer ses codes de récupération avec invalidation des anciens.
- Fournir les endpoints attendus par le client mobile (PD-106) pour l'écran Settings/MFA.
- Appliquer un rate limiting sur ces endpoints pour prévenir les abus.
3. Non-objectifs (exclusions explicites)¶
- Pas de validation MFA à l'authentification — couvert par PD-27.
- Pas de gestion de profil — couvert par PD-32.
- Pas de changement de mot de passe — user story distincte à créer.
- Pas de suppression de compte — user story distincte à créer.
- Pas de logout — user story distincte à créer.
- Pas de MFA par SMS, email ou WebAuthn — seul TOTP est supporté dans cette version.
- Pas d'implémentation TOTP native — délégation à Keycloak.
4. Contraintes¶
Sécurité¶
- Authentification obligatoire : tous les endpoints
/user/mfa/*requièrent un JWT valide. - Re-authentification pour opérations sensibles : désactivation MFA et régénération des codes de récupération exigent une re-authentification récente (< 5 minutes).
- Secrets jamais loggués : le secret TOTP et les codes de récupération ne doivent jamais apparaître dans les logs applicatifs.
- Rate limiting : protection contre les tentatives de bruteforce sur la vérification TOTP.
- RLS : un utilisateur ne peut gérer que son propre MFA.
Techniques¶
- Cohérence avec PD-106 : le contrat d'API doit être compatible avec ce que le client mobile attend.
- Intégration Keycloak : utilisation de l'Admin REST API ou Account API de Keycloak pour la gestion MFA.
- Cohérence avec l'architecture existante : NestJS, DTOs avec class-validator, Swagger, guards existants.
Réglementaires¶
- Pas de stockage de secrets MFA côté ProbatioVault : tous les secrets sont gérés par Keycloak (conformité PD-27 §I3).
5. Scénarios d'échec et résultats inacceptables¶
- Fuite du secret TOTP : le secret apparaît dans les logs, réponses d'erreur ou est persisté côté backend.
- Activation MFA sans vérification : le MFA est activé sans que l'utilisateur ait prouvé qu'il possède le code TOTP.
- Désactivation MFA sans re-authentification : un attaquant avec une session volée peut désactiver le MFA.
- Codes de récupération non invalidés : après régénération, les anciens codes restent valides.
- Accès croisé : un utilisateur A peut consulter ou modifier le MFA d'un utilisateur B.
- Incohérence avec PD-106 : le client mobile reçoit un contrat d'API différent de ce qu'il attend.
6. Endpoints cibles¶
6.1 GET /user/mfa/status¶
Retourne l'état MFA de l'utilisateur courant.
Réponse attendue :
6.2 POST /user/mfa/totp/init¶
Initialise la configuration TOTP. Retourne le secret et l'URI pour générer un QR code.
Réponse attendue :
{
"secret": "JBSWY3DPEHPK3PXP",
"qrCodeUri": "otpauth://totp/ProbatioVault:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ProbatioVault",
"expiresAt": "2026-02-06T12:00:00Z"
}
Note : le secret n'est pas encore actif, il doit être vérifié via /totp/verify.
6.3 POST /user/mfa/totp/verify¶
Vérifie le code TOTP fourni par l'utilisateur et active le MFA si correct.
Body :
Réponse succès :
Les codes de récupération ne sont retournés qu'une seule fois, à l'activation.
6.4 POST /user/mfa/disable¶
Désactive le MFA de l'utilisateur. Requiert re-authentification.
Headers requis : X-Reauth-Token ou mécanisme équivalent prouvant re-authentification récente.
Réponse succès :
6.5 POST /user/mfa/recovery/regenerate¶
Régénère les codes de récupération. Invalide tous les codes précédents. Requiert re-authentification.
Réponse succès :
6.6 POST /auth/reauth¶
Endpoint de re-authentification pour les opérations sensibles.
Body :
Réponse succès :
Le token est un JWT signé avec : - sub : ID utilisateur - purpose : "reauth" (évite réutilisation pour autre chose) - exp : expiration à 5 minutes
Le client envoie ce token via header X-Reauth-Token pour les opérations sensibles.
7. Décisions techniques¶
| Question | Décision | Justification |
|---|---|---|
| API Keycloak | Admin API | Le backend agit comme proxy avec service account. Permet validations métier avant action. Cohérent avec l'architecture (backend = point d'entrée unique). |
| Codes de récupération | 15 codes | Défaut Keycloak, évite configuration custom. |
| Format reauthToken | JWT signé | Stateless, cohérent avec auth existante. Claims : sub, purpose: "reauth", exp (TTL 5 min). |