You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(auth): make Unlock Account release the second factor too (#3690)
`unlockUser` reset only `sys_user.failed_login_count` / `locked_until`. Sign-in
can lock at either stage and the two counters are independent, so a user locked
at the second factor had no admin escape hatch at all — the only way out was
waiting the duration out.
That was survivable while the second-factor lock needed better-auth's 10
failures. Now that the threshold is operator-configurable and 3 is a reasonable
choice, it is a lock admins will hit routinely, so the action has to cover it.
The second-factor clear is best-effort and runs after the primary write: an
account with no enrolment, or an environment where 2FA was never switched on,
must still get the unlock the admin asked for.
Covered by two unit tests (both enrolments cleared; a failing lookup does not
sink the unlock) and an end-to-end one that re-locks the account, unlocks it
through `/auth/admin/unlock-user`, and signs in again. The end-to-end test takes
its admin session BEFORE re-locking — after the lock there is no way to obtain
one, which is the whole reason the escape hatch has to exist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYLC8TfjzHGwatNxZKdX7H
Copy file name to clipboardExpand all lines: content/docs/permissions/authentication.mdx
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -456,13 +456,14 @@ code that reads it). Changes take effect immediately; no restart is required.
456
456
| Setting | Effect |
457
457
|---|---|
458
458
|`lockout_threshold`| Lock an account after this many consecutive failed sign-in attempts. Counts **both** stages: wrong passwords and wrong two-factor codes. |
459
-
|`lockout_duration_minutes`| How long a lockout lasts, at either stage. Admins can clear a password-stage lockout early with the **Unlock** action on the user record. |
459
+
|`lockout_duration_minutes`| How long a lockout lasts, at either stage. Admins can clear it early with the **Unlock** action on the user record, which releases both stages. |
460
460
|`rate_limit_max` / `rate_limit_window_seconds`| Per-IP request throttle on auth endpoints. |
461
461
462
462
The two stages keep **separate counters** — `sys_user.failed_login_count` for the
463
463
password check, `sys_two_factor.failed_verification_count` for the second factor —
464
464
so a locked password stage and a locked second factor are independent states. Each
465
-
counter resets on a success at its own stage.
465
+
counter resets on a success at its own stage, and the admin **Unlock Account**
466
+
action clears both at once.
466
467
467
468
Setting `lockout_threshold` to `0` disables the **password-stage** lockout only.
468
469
Two-factor verification keeps a built-in limit of 10 attempts per 15 minutes,
0 commit comments