Authentication

OAuth 2.0 + MFA implementation for enterprise security.

Stack

LayerTechnology
BackendFastAPI + SQLAlchemy 2.0 (async)
AuthJWT (python-jose) + bcrypt (passlib)
MFATOTP (pyotp) + QR codes (qrcode)
FrontendNext.js 14 + React Context

Architecture

┌──────────────┐    POST /login     ┌──────────────┐
│   Frontend   │ ─────────────────► │   FastAPI    │
│  Next.js 14  │                    │   Backend    │
└──────────────┘                    └──────────────┘
       │                                   │
       │ 1. Credentials                    │ 2. Verify (bcrypt)
       │                                   │
       │ 3. JWT Token                      │ 3. Create JWT
       │ ◄─────────────────────────────────│    (sub, role, mfa)
       │                                   │
       │ 4. MFA Required?                  │
       │    ├─ No → Done                   │
       │    └─ Yes → Show OTP input        │
       │                                   │
       │ 5. POST /mfa/challenge            │
       │ ─────────────────────────────────►│
       │                                   │ 5. Verify TOTP
       │ 6. New JWT (mfa=true)             │
       │ ◄─────────────────────────────────│

Token Structure

{
  "sub": "user@example.com",
  "role": "analyst",
  "mfa": true,
  "exp": 1710000000
}

API Endpoints

MethodEndpointPurpose
POST/api/users/loginOAuth2 password grant
GET/api/users/meGet current user
POST/api/users/mfa/setupGenerate TOTP secret + QR
POST/api/users/mfa/verifyEnable MFA
POST/api/users/mfa/challengeVerify OTP during login

Key Files

apps/api/
├── app/services/
│   ├── auth_service.py    # JWT, password hashing
│   └── mfa_service.py     # TOTP, QR generation
├── app/routers/
│   └── users.py           # Auth endpoints
└── tests/
    └── test_auth.py       # 21 unit tests

Test Coverage

21 tests • 100% pass rate

├── Password Hashing (6 tests)
├── JWT Tokens (5 tests)
├── MFA Service (5 tests)
└── Login Flows (5 tests)

Run tests:

cd apps/api && pytest tests/ -v

Security Features

  • Passwords hashed with bcrypt (unique salts)
  • JWT signed with HS256 (24h expiry)
  • MFA via RFC 6238 TOTP (Google Authenticator compatible)
  • Tokens invalidated on 401 (auto-logout)
  • M-25-21 compliance: Analysts save drafts, reviewers commit