This document covers the password change and TOTP-based two-factor authentication flows implemented by the auth service.
- All password and MFA operations live in
cmd/auth. - V1 supports one active TOTP factor per user.
- Email recovery is only a login fallback. It is not accepted for password changes, disabling 2FA, or regenerating recovery codes.
- Route:
POST /api/v1/auth/password/change - Requires an authenticated access token.
- Request body always includes
current_passwordandnew_password. - If 2FA is enabled, the same request must also include
code_type(totporrecovery_code) andcode. - Success returns fresh access and refresh tokens for the current client and revokes older sessions.
- Call
POST /api/v1/auth/2fa/totp/setupwith the current password. - The auth service returns a short-lived TOTP setup payload with:
setup_idotpauth_urimanual_keyissueraccount_nameexpires_at
- The client renders the QR locally from
otpauth_uri. - Call
POST /api/v1/auth/2fa/totp/confirmwithsetup_idand a 6-digit authenticator code. - Success enables TOTP, returns fresh tokens, and returns recovery codes once.
POST /api/v1/auth/loginstill validates email and password first.- When TOTP is enabled, it responds with
202 Acceptedand achallenge_id. - The client completes the second step with one of:
POST /api/v1/auth/login/2fa/totpPOST /api/v1/auth/login/2fa/recovery-codePOST /api/v1/auth/login/2fa/email/startfollowed byPOST /api/v1/auth/login/2fa/email/verify
- Successful verification returns normal access and refresh tokens.
POST /api/v1/auth/2fa/recovery-codes/regeneraterequires the current password plus a TOTP or recovery code.DELETE /api/v1/auth/2farequires the current password plus a TOTP or recovery code.- Both operations rotate the session version and invalidate older sessions.
- PostgreSQL stores:
authentications.session_versionauth_factorsauth_totp_factorsauth_recovery_codes
- TOTP secrets are encrypted before storage.
- Recovery codes are stored only as one-time password hashes.
- Redis/KeyDB stores pending TOTP setup state with a 10-minute TTL.
- Redis/KeyDB stores login challenge state with a 5-minute TTL, attempt counters, and email recovery metadata.
- Password changes, TOTP enable, TOTP disable, and recovery-code regeneration bump
session_version. - JWTs now carry
session_version. - HTTP middleware and the WebSocket gateway validate that claim against Redis/KeyDB with PostgreSQL fallback.
- After a successful security mutation, auth publishes a user-scoped revocation event so existing WebSocket sessions close and reconnect with fresh tokens only.
- Config adds
mfa_encryption_keyfor TOTP secret encryption. - Config adds
mfa_recovery_templatefor the email recovery code template. - Auth service rate limits now cover:
- password login attempts by email and IP
- second-step verification attempts by challenge and IP
- email recovery sends by user and IP, including a resend cooldown