MFA recovery codes and self-service disable
Recovery codes
- Recovery codes are stored as hashes; plaintext is shown only once when the user generates or regenerates codes. There is no API to retrieve plaintext later.
- Metadata (how many unused codes exist, when the current set was last generated) is available via:
- GraphQL:
myMfaRecoveryCodeStatus - REST:
GET /api/me/mfa/recovery-codes/status
- GraphQL:
- Regenerating invalidates previous unused codes (soft-delete + new set), consistent with a single active batch per user.
MFA challenge: TOTP vs recovery
- Server-side guards rely on
mfaVerifiedon the JWT (see MFA GraphQL/REST guards), not on client-only state. - Completing a challenge with a recovery code must use the auth surface—same session elevation as TOTP verification:
- GraphQL:
verifyMfaRecoveryCode - REST:
POST /api/auth/mfa/recovery/verify
- GraphQL:
- That path verifies the code, marks the session MFA-verified, and returns rotated access/refresh tokens (and refresh cookie where applicable), mirroring
verifyMfa.
Self-service disable (single-primary TOTP model)
- The product allows users to turn off MFA by removing their last registered factor.
- When no active factors remain, the platform revokes all recovery codes (soft-delete active rows) and records an audit action such as
MFA_DISABLEDwithreason: last_factor_removed. - Multi-device promotion (remove primary → promote another device) is out of scope until the data model supports multiple active factors beyond the current primary-only enrollment path.
Organization policy vs user choice
- If
requireMfaForSensitiveActionsis enabled for an organization, sensitive org actions may still require MFA server-side even if the user has disabled MFA on their account. The user will see MFA-required flows until they enroll and verify again; this is intentional: self-service disable does not weaken server enforcement for those routes.
See also
- Security & session management — MFA guards, min-AAL, JWT
mfaVerified
References
- Handlers:
AuthHandler.verifyMfa,AuthHandler.verifyMfaRecoveryCode - Service:
UserMfaService(verify recovery, remove last factor + revoke codes) - Web: settings recovery card (one-time display + metadata), MFA challenge page (auth recovery mutation + tokens)