Authentication — Architecture¶
Audience: Architects, tech leads, senior engineers evaluating design decisions.
This content was migrated from
Documentation/TWO_FACTOR_AUTH.mdand restructured into audience sections. Review for accuracy against the current codebase.
Context and Purpose¶
The Authentication module exists to protect admin-level access to Swisper with a second factor beyond passwords. Admin users can view and modify system configuration, user data, and AI tuning parameters — a compromise would have platform-wide impact. TOTP-based 2FA is a well-understood standard (RFC 6238) that works with any authenticator app, requiring no additional infrastructure like SMS gateways or push notification services.
Architecture Overview¶
graph TD
subgraph Setup ["2FA Setup"]
S1["POST /admin/2fa/setup"] --> S2["Generate TOTP secret\n(pyotp)"]
S2 --> S3["Generate QR code\n(qrcode SVG)"]
S3 --> S4["Return secret + QR"]
S4 --> S5["POST /admin/2fa/verify-setup"]
S5 --> S6["Verify code\nEncrypt + store secret\nGenerate backup codes"]
end
subgraph Login ["Login with 2FA"]
L1["POST /login/access-token\n(email + password)"] --> L2{"totp_enabled?"}
L2 -->|"No"| L3["Return full session"]
L2 -->|"Yes"| L4["Return partial token\n(5 min expiry)"]
L4 --> L5["POST /login/verify-2fa\n(partial token + code)"]
L5 --> L6["Verify TOTP or\nbackup code"]
L6 --> L3
end
subgraph Storage ["Data at Rest"]
DB["User Model\n(PostgreSQL)"]
ENC["totp_secret\n(PGPString encrypted)"]
HASH["totp_backup_codes\n(bcrypt hashed)"]
DB --- ENC
DB --- HASH
end
Component Responsibilities¶
| Component | Responsibility |
|---|---|
2FA Routes (routes.py) |
API endpoints for setup, verify-setup, and backup code regeneration |
2FA Service (service.py) |
TOTP secret generation, code verification, backup code generation (bcrypt hashing), secret encryption/decryption |
Login Route (login.py) |
Integrates 2FA step into existing login flow; issues partial vs full session tokens |
User Model (persistence/models.py) |
Stores encrypted TOTP secret, enabled flag, backup codes, timestamps |
Key Design Decisions¶
Decision 1: Partial session token for 2FA step
- Chosen: After password verification, issue a short-lived partial token (5 min) that can only be used for the
verify-2faendpoint. - Rejected: Keeping the full session and requiring 2FA before sensitive operations.
- Rationale: A partial token ensures the user has zero access until 2FA is complete. The 5-minute expiry limits the window for interception.
Decision 2: Backup codes as bcrypt hashes
- Chosen: Store backup codes as bcrypt hashes; single-use (deleted after use).
- Rejected: Storing backup codes encrypted (reversible) or not at all.
- Rationale: bcrypt is irreversible and intentionally slow, making brute-force attacks impractical — even database access doesn't reveal backup codes. Single-use prevents replay attacks.
Known Trade-offs and Debt¶
- No rate limiting on TOTP attempts: The
totp_last_used_atfield exists but rate limiting is not yet implemented. A brute-force attack on the 6-digit code (1M combinations) is theoretically possible without rate limiting, though the 30-second TOTP window limits practical attempts. - No audit logging: 2FA enable/disable events are not logged to an audit trail. This makes it harder to investigate unauthorized changes.
- Admin-only scope: Regular users have no 2FA option. Extending to all users would require frontend changes and a migration strategy for existing sessions.