Lockout brute-force
Verrouillage progressif des comptes en cas de tentatives échouées.
Au bout de 3 mauvais mots de passe consécutifs, le compte se verrouille pour une durée croissante. Le compteur se reset tout seul après 24h sans nouvelle tentative.
Progression
Définie dans lib/auth-lockout.ts :
export const FAILS_BEFORE_LOCK = 3;
export const LOCKOUT_MINUTES = [10, 20, 30, 45, 60];| Échec n° | Verrouillage |
|---|---|
| 1, 2 | Aucun, juste un compteur qui monte |
| 3 | 10 min |
| 4 | 20 min |
| 5 | 30 min |
| 6 | 45 min |
| 7+ | 60 min (cap) |
Au-delà du 7e échec, on reste à 60 min — on ne punit pas indéfiniment.
Decay 24h
Si la dernière tentative ratée date de plus de 24h, le compteur repart à zéro. Constante :
const ATTEMPT_DECAY_MS = 24 * 60 * 60 * 1000;Pas de cron nécessaire — la décrémentation est lazy, calculée à la prochaine tentative de login.
Champs Prisma
Trois colonnes sur User :
failedLoginAttempts Int @default(0)
lastFailedLoginAt DateTime?
lockedUntil DateTime?API helpers (lib/auth-lockout.ts)
recordFailedAttempt(userId) // appelé sur mot de passe faux
clearLockout(userId) // appelé sur login réussi
adminUnlockUser(userId) // déverrouillage manuel admin
getLockState({...}) // lecture sans mutationRoute publique de status
GET /api/auth/lock-status?email=foo@bar.com retourne l'état actuel du
verrouillage. Utilisée par la page de login pour afficher un message
"Compte verrouillé pendant X minutes" sans révéler si l'email existe
(retourne { locked: false, attempts: 0 } si user inconnu).
Action admin "déverrouiller"
Sur la page /admin/users, l'action Déverrouiller apparaît si
lockedUntil > now. Elle appelle adminUnlockUser qui réinitialise les
trois champs. Audit loggé via user.unlock.
Allez plus loin
- Audit log — tracer les verrouillages
- Dashboard admin — section Users
- Authentification