feat: enterprise MFA with TOTP, email codes, backup codes, and trusted devices

Three verification methods (TOTP authenticator, email code, backup codes),
trusted device management with 30-day expiry, role-based enforcement for
super_admin and org_admin, admin reset capability, and full test coverage
(46 tests). Modifies login flow to support MFA challenge/response with
temporary session tokens stored in cache.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 20:45:55 +02:00
parent df68aa8aef
commit 948687f27e
32 changed files with 2563 additions and 5 deletions

View File

@@ -13,6 +13,41 @@ Auth: Bearer token (Sanctum) — token delivered via httpOnly cookie, never in t
- `POST /auth/forgot-password` — request password reset (public, rate-limited). Body: `{ email, app: "app"|"portal"|"admin" }`. Always returns 200 (no email enumeration).
- `POST /auth/reset-password` — reset password with token (public). Body: `{ token, email, password, password_confirmation }`.
## MFA (Multi-Factor Authentication)
### Login flow with MFA
When MFA is enabled for a user, login becomes a two-step process:
1. `POST /auth/login` — if MFA is active, returns `{ mfa_required: true, mfa_session_token, methods, preferred_method, expires_in }` instead of the auth token
2. `POST /auth/mfa/verify` — submit the MFA code with the session token to complete login
If the device is trusted (via `X-Device-Fingerprint` header), MFA is bypassed and login proceeds normally.
### MFA verification during login (public, rate-limited)
- `POST /auth/mfa/verify` — verify MFA code during login. Body: `{ mfa_session_token, code, method: "totp"|"email"|"backup_code", trust_device?: bool, device_fingerprint?: string, device_name?: string }`. Returns user data + auth cookie on success.
- `POST /auth/mfa/email/send` — send/resend email verification code during login. Body: `{ mfa_session_token }`. Rate-limited: 1 code per 60 seconds.
### MFA setup and management (authenticated)
- `POST /auth/mfa/setup/totp` — start TOTP setup, returns `{ secret, qr_code_url, provisioning_uri }`
- `POST /auth/mfa/setup/totp/confirm` — confirm TOTP with first code. Body: `{ code }`. Returns `{ mfa_enabled, method, backup_codes[] }`
- `POST /auth/mfa/setup/email` — start email MFA setup (sends verification code)
- `POST /auth/mfa/setup/email/confirm` — confirm email MFA. Body: `{ code }`. Returns `{ mfa_enabled, method, backup_codes[] }`
- `POST /auth/mfa/disable` — disable MFA. Body: `{ code, method: "totp"|"backup_code" }`. Requires valid verification code.
- `POST /auth/mfa/backup-codes` — regenerate backup codes. Body: `{ code }`. Requires valid TOTP code.
- `GET /auth/mfa/status` — current MFA status: `{ mfa_enabled, method, confirmed_at, backup_codes_remaining, is_required }`
### Trusted devices (authenticated)
- `GET /auth/trusted-devices` — list active trusted devices
- `DELETE /auth/trusted-devices/{id}` — revoke a specific device
- `DELETE /auth/trusted-devices` — revoke all devices
### Admin MFA management (super_admin)
- `POST /admin/users/{user}/reset-mfa` — force-disable MFA for a user. Activity logged.
## Account Management (authenticated)
- `POST /me/change-password` — change own password. Body: `{ current_password, password, password_confirmation }`. Revokes other sessions.