Date : 2026-06-16
Heure : 10:58
Références analysées :
- flow_connexion.md — Flow de connexion Caritas
- 3_REFERENCE_GESTION_SESSIONS.md — Référence gestion des sessions
Flow connexion (flow_connexion.md)
Toutes les étapes clés sont implémentées : vérification utilisateur, bcrypt, verrouillage 5 tentatives/30 min, génération tokens JWT 24h/7j, session en BD, audit LOGIN, retour du profil + tokens.
⚠️ Écarts — Connexion simple
| Étape spec |
Écart |
Fichier concerné |
| Vérification email confirmé |
TODO commenté (EC-3 ligne 208) — le champ emailVerifie n'existe pas encore dans le schéma Prisma |
ConnexionUseCase.ts L.207-211 |
| Localisation stockée en session |
IP et UserAgent sont stockés, mais la localisation géographique est absente |
SessionAuthRepositoryPrisma.ts |
| Max 5 tentatives 2FA |
La spec dit 5, mais incrementerTentativesEchouees retourne 0 au 3ème essai échoué — à vérifier dans SessionAuthRepositoryPrisma |
Verifier2FAUseCase.ts L.259-288 |
- Détection 2FA actif (
utilisateur.deuxFacteursActive) ✅
- Code EMAIL 6 chiffres, stocké en BD, validité 15 min ✅
- Méthode TOTP → aucun code envoyé ✅
- Session temporaire créée (10 min) ✅
- Retour
requires2FA: true + méthode 2FA ✅
- Validation code EMAIL (existence, non-expiré, non-utilisé) ✅
- Validation TOTP avec fenêtre ±30 secondes ✅
- Marquage code comme utilisé après validation ✅
- Audit
2FA_VERIFIED ✅
- Génération tokens JWT + session définitive ✅
- Invalidation session temporaire ✅
⚠️ Écart — Refresh Token
La spec dit "conserver le même refresh token sauf si proche expiration", mais l'implémentation fait une rotation systématique (enableRefreshTokenRotation: true dans RefreshTokenUseCase.ts L.56).
→ C'est plus sécurisé mais ne suit pas la spec à la lettre.
| Erreur spec |
Code implémenté |
| Email inexistant |
CREDENTIALS_INVALIDES |
| Mot de passe incorrect |
CREDENTIALS_INVALIDES |
| Compte bloqué |
COMPTE_VERROUILLE / COMPTE_INACTIF |
| Code 2FA invalide |
CODE_INVALIDE |
| Session 2FA expirée |
SESSION_EXPIREE |
| Refresh Token expiré |
REFRESH_TOKEN_EXPIRE |
| Session révoquée |
SESSION_INVALIDE |
| IP bloquée |
IP_BLOQUEE |
Référence gestion des sessions (3_REFERENCE_GESTION_SESSIONS.md)
| Aspect |
Valeur implémentée |
| Bibliothèque JWT |
jose (conforme recommandation Opt-A) |
| Algorithme |
HS256 |
| Access Token |
24h (JWT_ACCESS_EXPIRES) |
| Refresh Token |
7 jours (JWT_REFRESH_EXPIRES) |
| Issuer |
caritas-questionnaire-system |
| Hachage token en BD |
SHA256 (crypto.createHash('sha256')) |
| Hachage mot de passe |
bcryptjs (ServiceHashage.ts) |
| Rotation tokens au refresh |
✅ activée par défaut |
| Pub/Sub Redis |
✅ SESSION_CREATED via publishSessionEvent |
| 2FA TOTP |
otplib via Service2FA.ts |
| 2FA Email |
Nodemailer via ServiceEmail.ts |
| Brute-force protection |
5 tentatives → 30 min lockout |
| Payload JWT |
idUtilisateur, email, role, permissions, sessionId |
| Endpoints sessions |
Lister, révoquer une, révoquer toutes ✅ |
⚠️ Écarts — Référence sessions
| Point référence |
Écart |
Flag emailVerifie |
Recommandé dans la référence, absent du schéma Prisma (même TODO EC-3 que ci-dessus) |
| Redis blacklist avant BD |
Le diagramme de la référence met Redis en premier (EXISTS jwt:blacklist:{sessionId}), mais RefreshTokenUseCase interroge la BD en premier. Redis est utilisé uniquement pour les événements Pub/Sub, pas pour la blacklist. |
Synthèse
Le module est solide et largement conforme aux deux références.
Points ouverts prioritaires
| Priorité |
Point |
Action |
| 1 |
emailVerifie absent du schéma Prisma |
Ajouter le champ au schéma + migration prisma db push + décommenter la vérification dans ConnexionUseCase.ts L.207-211 |
| 2 |
Limite tentatives 2FA à confirmer |
Vérifier SessionAuthRepositoryPrisma.incrementerTentativesEchouees — doit bloquer à 5 tentatives et non 3 |
| 3 |
Redis blacklist absente |
Ajouter vérification jwt:blacklist:{sessionId} dans RefreshTokenUseCase avant la requête BD |
Points acceptés (divergences volontaires)
- Rotation systématique du Refresh Token : plus sécurisé que la spec, aucune action requise.
- Localisation géographique absente : optionnelle selon la spec, non bloquante.