System15 / hld.md
yamilogic's picture
Deploy SMTP Auth System to Hugging Face Space
50535d1
|
Raw
History Blame Contribute Delete
47 kB
# Auth-System-SMTP β€” High-Level Design (HLD)
---
## 1. System Overview
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ CLIENT (Browser) β”‚
β”‚ React 18 + Vite (Port 5173) β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Register β”‚ β”‚ Login β”‚ β”‚ Verify β”‚ β”‚ Dashboard β”‚ β”‚
β”‚ β”‚ Page β”‚ β”‚ Page β”‚ β”‚ Email β”‚ β”‚ (Profile/Admin) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ AuthContext (State) β”‚ β”‚
β”‚ β”‚ + Axios Interceptors (Token) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ HTTP/HTTPS
β”‚ Authorization: Bearer <token>
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ API SERVER (FastAPI) β”‚
β”‚ (Port 8000, Uvicorn) β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Middleware Layer β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ CORS β”‚ β”‚ Rate Limiter β”‚ β”‚ Request Logger β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ Middlewareβ”‚ β”‚ (60 req/min) β”‚ β”‚ (IP, method, path) β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Route Handlers β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ Auth Routes (/auth) User Routes (/me, /admin) β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ register β”‚ β”‚ GET /me β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ verify-email β”‚ β”‚ PUT /me β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ login β”‚ β”‚ DELETE /me β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ forgot-password β”‚ β”‚ GET /admin/users β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ reset-password β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ refresh β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ logout β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Core Services β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ Auth β”‚ β”‚ Config β”‚ β”‚ Database Manager β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ Service β”‚ β”‚ Loader β”‚ β”‚ (SQLAlchemy Engine) β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ bcrypt β”‚ β”‚ .env β”‚ β”‚ SQLite3 Connection β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ JWT β”‚ β”‚ variables β”‚ β”‚ Session Factory β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ SMTP Send β”‚ β”‚ β”‚ β”‚ Base (ORM) β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β–Ό β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ SMTP SERVER β”‚ β”‚ SQLite Database β”‚
β”‚ (Gmail / Console) β”‚ β”‚ (users.db) β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ smtp.gmail.com β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ Port 587 (STARTTLS) β”‚ β”‚ β”‚ users β”‚ β”‚revoked_tokensβ”‚ β”‚
β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ Sends OTP emails: β”‚ β”‚ β”‚
β”‚ - Email Verify β”‚ β”‚ Tables: β”‚
β”‚ - Password Reset β”‚ β”‚ - users β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ - revoked_tokens β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## 2. Component Architecture
### 2.1 Backend Components
```
backend/
β”œβ”€β”€ main.py ← FastAPI app, CORS, rate limiting, middleware
β”œβ”€β”€ config.py ← Loads .env variables via python-dotenv
β”œβ”€β”€ database.py ← SQLAlchemy engine + session + Base
β”œβ”€β”€ models.py ← ORM models: User, RevokedToken
β”œβ”€β”€ schemas.py ← Pydantic request/response schemas
β”œβ”€β”€ auth.py ← Password hashing, JWT, SMTP email
β”œβ”€β”€ routes/
β”‚ β”œβ”€β”€ auth_routes.py ← /auth endpoints (register, login, etc.)
β”‚ └── user_routes.py ← /me and /admin endpoints
└── .env ← Environment variables (secrets)
```
**Data Flow:**
```
Request β†’ Middleware (CORS, Rate Limit, Logging)
β†’ Route Handler (auth_routes / user_routes)
β†’ Auth Service (validate token, hash password, send email)
β†’ Database (SQLAlchemy ORM β†’ SQLite)
β†’ Response (JSON)
```
### 2.2 Frontend Components
```
frontend/
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ main.jsx ← Entry point, BrowserRouter
β”‚ β”œβ”€β”€ App.jsx ← Root component, all routes
β”‚ β”œβ”€β”€ index.css ← Global styles (glassmorphism)
β”‚ β”œβ”€β”€ api/
β”‚ β”‚ └── axios.js ← Axios instance + interceptors
β”‚ β”œβ”€β”€ context/
β”‚ β”‚ └── AuthContext.jsx ← Auth state management
β”‚ β”œβ”€β”€ components/
β”‚ β”‚ β”œβ”€β”€ Navbar.jsx ← Navigation bar
β”‚ β”‚ └── ProtectedRoute.jsx ← Route guard
β”‚ └── pages/
β”‚ β”œβ”€β”€ Register.jsx ← Registration form
β”‚ β”œβ”€β”€ Login.jsx ← Login form
β”‚ β”œβ”€β”€ VerifyEmail.jsx ← OTP verification form
β”‚ └── Dashboard.jsx ← User dashboard + admin panel
```
**Component Hierarchy:**
```
<App>
β”œβ”€β”€ <AuthProvider> (Context)
β”‚ β”œβ”€β”€ <Navbar />
β”‚ β”œβ”€β”€ <Routes>
β”‚ β”‚ β”œβ”€β”€ /register β†’ <Register />
β”‚ β”‚ β”œβ”€β”€ /login β†’ <Login />
β”‚ β”‚ β”œβ”€β”€ /verify-email β†’ <VerifyEmail />
β”‚ β”‚ └── /dashboard β†’ <ProtectedRoute> β†’ <Dashboard />
β”‚ β”‚ └── / β†’ <Navigate to="/login" />
```
---
## 3. Authentication Flow Diagrams
### 3.1 Registration Flow
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client β”‚ β”‚ Server β”‚ β”‚ SMTP β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ β”‚
β”‚ POST /auth/register β”‚ β”‚
β”‚ { username, email, password } β”‚ β”‚
│────────────────────────────────────────▢│ β”‚
β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ β”‚ Validate: β”‚ β”‚
β”‚ β”‚ - Email len β”‚ β”‚
β”‚ β”‚ - Password β”‚ β”‚
β”‚ β”‚ strength β”‚ β”‚
β”‚ β”‚ - Uniquenessβ”‚ β”‚
β”‚ └────────────── β”‚
β”‚ β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚ β”‚ bcrypt.hash β”‚ β”‚
β”‚ β”‚ + OTP gen β”‚ β”‚
β”‚ β”‚ + Create β”‚ β”‚
β”‚ β”‚ User β”‚ β”‚
β”‚ └────────────── β”‚
β”‚ β”‚ β”‚
β”‚ β”‚ Send OTP via SMTP β”‚
β”‚ │──────────────────────────────▢│
β”‚ β”‚ β”‚
β”‚ 200 OK (redirect to /verify-email) β”‚ β”‚
│◀────────────────────────────────────────│ β”‚
β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ β”‚ Console fallback: β”‚ β”‚
β”‚ β”‚ β”‚ Print OTP if SMTP failsβ”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
```
### 3.2 Login Flow
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client β”‚ β”‚ Server β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ POST /auth/login β”‚
β”‚ (OAuth2 form: username + password) β”‚
│────────────────────────────────────────▢│
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Look up β”‚
β”‚ β”‚ user by β”‚
β”‚ β”‚ username β”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ bcrypt β”‚
β”‚ β”‚ .checkpw() β”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Check: β”‚
β”‚ β”‚ - is_active β”‚
β”‚ β”‚ - is_verifiedβ”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Generate: β”‚
β”‚ β”‚ - access_token β”‚
β”‚ β”‚ - refresh_token β”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ 200 OK β”‚
β”‚ { access_token, refresh_token } β”‚
│◀────────────────────────────────────────│
β”‚ β”‚
β”‚ Store in sessionStorage β”‚
β”‚ Set AuthContext user β”‚
```
### 3.3 Token Refresh Flow
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client β”‚ β”‚ Server β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ API Request with expired access_token β”‚
│────────────────────────────────────────▢│
β”‚ β”‚
β”‚ 401 Unauthorized β”‚
│◀────────────────────────────────────────│
β”‚ β”‚
β”‚ Axios interceptor detects 401 β”‚
β”‚ β”‚
β”‚ POST /auth/refresh β”‚
β”‚ { refresh_token } β”‚
│────────────────────────────────────────▢│
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Decode JWT β”‚
β”‚ β”‚ Check type β”‚
β”‚ β”‚ == "refresh"β”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Check if β”‚
β”‚ β”‚ revoked β”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Revoke old β”‚
β”‚ β”‚ refresh tokenβ”‚
β”‚ β”‚ (rotation) β”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Issue new β”‚
β”‚ β”‚ access + β”‚
β”‚ β”‚ refresh pairβ”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ 200 OK β”‚
β”‚ { access_token, refresh_token } β”‚
│◀────────────────────────────────────────│
β”‚ β”‚
β”‚ Retry original request with new token β”‚
│────────────────────────────────────────▢│
β”‚ β”‚
β”‚ 200 OK (success) β”‚
│◀────────────────────────────────────────│
```
### 3.4 Logout Flow
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Client β”‚ β”‚ Server β”‚
β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ POST /auth/logout β”‚
β”‚ { refresh_token } β”‚
β”‚ Authorization: Bearer <access_token> β”‚
│────────────────────────────────────────▢│
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ Insert both β”‚
β”‚ β”‚ tokens into β”‚
β”‚ β”‚ revoked_ β”‚
β”‚ β”‚ tokens tableβ”‚
β”‚ └──────────────
β”‚ β”‚
β”‚ 200 OK β”‚
│◀────────────────────────────────────────│
β”‚ β”‚
β”‚ Clear sessionStorage β”‚
β”‚ Set user = null β”‚
β”‚ Redirect to /login β”‚
```
---
## 4. Data Models
### 4.1 Entity Relationship Diagram
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ users β”‚ β”‚ revoked_tokens β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ id INTEGER PK β”‚ β”‚ id INTEGER PK β”‚
β”‚ username VARCHAR UNI β”‚ β”‚ token VARCHAR UNI β”‚
β”‚ email VARCHAR UNI β”‚ β”‚ revoked_at DATETIME β”‚
β”‚ password VARCHAR β”‚ β”‚ expires_at DATETIME β”‚
β”‚ is_active BOOLEAN β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ role VARCHAR β”‚
β”‚ created_at DATETIME β”‚ Relationship: One user can have
β”‚ is_verified BOOLEAN β”‚ many revoked tokens (1:N)
β”‚ verification_code VARCHARβ”‚
β”‚ reset_code VARCHAR β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
### 4.2 User Model Fields
| Field | Type | Constraints | Default | Description |
|-------|------|-------------|---------|-------------|
| `id` | Integer | PK, auto-increment, indexed | β€” | Unique user identifier |
| `username` | String(50) | UNIQUE, NOT NULL, indexed | β€” | Login username |
| `email` | String(120) | UNIQUE, NOT NULL, indexed | β€” | User email address |
| `password` | String(255) | NOT NULL | β€” | bcrypt hashed password |
| `is_active` | Boolean | β€” | `True` | Account active status |
| `role` | String(10) | β€” | `"user"` | User role (user/admin) |
| `created_at` | DateTime | β€” | `datetime.utcnow()` | Registration timestamp |
| `is_verified` | Boolean | β€” | `False` | Email verified status |
| `verification_code` | String(6) | nullable | `None` | Registration OTP |
| `reset_code` | String(6) | nullable | `None` | Password reset OTP |
### 4.3 RevokedToken Model Fields
| Field | Type | Constraints | Default | Description |
|-------|------|-------------|---------|-------------|
| `id` | Integer | PK, auto-increment, indexed | β€” | Record identifier |
| `token` | String(512) | UNIQUE, NOT NULL, indexed | β€” | Full JWT string |
| `revoked_at` | DateTime | β€” | `datetime.utcnow()` | Revocation timestamp |
| `expires_at` | DateTime | NOT NULL | β€” | Token original expiry |
---
## 5. Security Architecture
### 5.1 Authentication & Authorization Layers
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ SECURITY LAYERS β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ Layer 1: Password Security β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ bcrypt hashing (salt + hash) β”‚ β”‚
β”‚ β”‚ Password strength validation (β‰₯8 chars, 1 letter, β”‚ β”‚
β”‚ β”‚ 1 digit) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 2: JWT Token Security β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Dual-token system (access 30min + refresh 7days) β”‚ β”‚
β”‚ β”‚ Token rotation on refresh (old token revoked) β”‚ β”‚
β”‚ β”‚ Token type validation (access vs refresh) β”‚ β”‚
β”‚ β”‚ Revocation checking on every request β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 3: Email Verification β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ OTP-based email verification β”‚ β”‚
β”‚ β”‚ 6-digit numeric code β”‚ β”‚
β”‚ β”‚ Must verify before login β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 4: Rate Limiting β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Global: 60 requests per 60 seconds per IP β”‚ β”‚
β”‚ β”‚ HTTP 429 when exceeded β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 5: CORS Protection β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Whitelist: localhost:5173, localhost:3000 β”‚ β”‚
β”‚ β”‚ Credentials allowed β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 6: Role-Based Access Control β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Admin-only endpoints (/admin/users) β”‚ β”‚
β”‚ β”‚ User role checking in route handlers β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 7: Input Validation β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Pydantic schemas for all inputs β”‚ β”‚
β”‚ β”‚ Email validation (EmailStr) β”‚ β”‚
β”‚ β”‚ Field length constraints β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Layer 8: Error Handling β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Generic error messages (no stack trace leak) β”‚ β”‚
β”‚ β”‚ Request logging for audit trail β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
### 5.2 Token Lifecycle
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ User Login β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Issue Access + β”‚
β”‚ Refresh Tokens β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ β”‚ β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”
β”‚ Use Access β”‚ β”‚ β”‚ Use Refresh β”‚
β”‚ Token (30min) β”‚ β”‚ β”‚ Token (7days) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β” β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”
β”‚ Token Expires β”‚ β”‚ β”‚ Refresh Used β”‚
β”‚ (401 Response) β”‚ β”‚ β”‚ (Token Rotation)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Issue New β”‚
β”‚ Send Refresh β”‚ β”‚ Access+Refresh β”‚
β”‚ Token to β”‚ β”‚ Pair β”‚
β”‚ /auth/refresh β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Old Refresh β”‚
β”‚ Token Revoked β”‚
β”‚ (stored in DB)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## 6. API Design
### 6.1 Request/Response Schemas
**Register Request:**
```json
POST /auth/register
{
"username": "string (3-50 chars)",
"email": "string (valid email)",
"password": "string (β‰₯8 chars, 1 letter, 1 digit)"
}
```
**Register Response:**
```json
200 OK
{
"message": "User registered successfully. Please verify your email."
}
```
**Login Request:**
```json
POST /auth/login
Content-Type: application/x-www-form-urlencoded
username=string&password=string
```
**Login Response:**
```json
200 OK
{
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"token_type": "bearer"
}
```
**Refresh Request:**
```json
POST /auth/refresh
{
"refresh_token": "eyJ..."
}
```
**Refresh Response:**
```json
200 OK
{
"access_token": "eyJ...",
"refresh_token": "eyJ..."
}
```
### 6.2 Error Response Format
```json
401 Unauthorized
{
"detail": "Invalid authentication credentials"
}
422 Validation Error
{
"detail": [
{
"loc": ["body", "password"],
"msg": "Password must be at least 8 characters with at least one letter and one digit",
"type": "value_error"
}
]
}
429 Too Many Requests
{
"detail": "Too many requests. Please try again later."
}
```
---
## 7. SMTP Email System
### 7.1 Email Flow
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Route β”‚ β”‚ Auth β”‚ β”‚ SMTP β”‚
β”‚ Handler │────▢│ Service │────▢│ Server β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ send_email()β”‚ β”‚ smtplib β”‚ β”‚ Gmail β”‚
β”‚ called β”‚ β”‚ STARTTLS β”‚ β”‚ Port 587 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”‚ (if SMTP not configured or fails)
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Console β”‚
β”‚ Fallback β”‚
β”‚ (print OTP) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
### 7.2 SMTP Configuration
| Setting | Value | Purpose |
|---------|-------|---------|
| Server | `smtp.gmail.com` | Gmail SMTP server |
| Port | `587` | STARTTLS encryption |
| Protocol | STARTTLS | Upgrades plain connection to TLS |
| Auth | Username + App Password | Gmail-specific authentication |
### 7.3 Email Templates Sent
**Email Verification:**
```
Subject: Verify your email - Auth System
Hello {username},
Your verification code is: {otp_code}
This code will expire in 10 minutes.
If you did not register, please ignore this email.
```
**Password Reset:**
```
Subject: Password Reset Request - Auth System
Hello {username},
Your password reset code is: {otp_code}
This code will expire in 10 minutes.
If you did not request this, please ignore this email.
```
---
## 8. Frontend State Management
### 8.1 AuthContext Flow
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ AuthContext β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ State: β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ user: null | { id, username, email, role, ... } β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Methods: β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ login(username, password) β”‚ β”‚
β”‚ β”‚ β†’ POST /auth/login β”‚ β”‚
β”‚ β”‚ β†’ Store tokens in sessionStorage β”‚ β”‚
β”‚ β”‚ β†’ Fetch user profile β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ logout() β”‚ β”‚
β”‚ β”‚ β†’ POST /auth/logout β”‚ β”‚
β”‚ β”‚ β†’ Clear sessionStorage β”‚ β”‚
β”‚ β”‚ β†’ Set user = null β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β”‚ Initialization (on mount): β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ 1. Check sessionStorage for access_token β”‚ β”‚
β”‚ β”‚ 2. If exists β†’ GET /me to validate β”‚ β”‚
β”‚ β”‚ 3. If valid β†’ set user state β”‚ β”‚
β”‚ β”‚ 4. If invalid β†’ clear session, set user = null β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
### 8.2 Axios Interceptor Chain
```
Request Flow:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ API │───▢│ Request │───▢│ Server │───▢│ Response β”‚
β”‚ Call β”‚ β”‚ Interceptor β”‚ β”‚ β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ Attach Bearer token β”‚
β”‚ from sessionStorage β”‚
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Response Interceptor β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ If 401: β”‚
β”‚ 1. POST /auth/refresh β”‚
β”‚ 2. Update tokens β”‚
β”‚ 3. Retry request β”‚
β”‚ 4. If fail β†’ /login β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## 9. Deployment Architecture
### 9.1 Development Setup
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Development Environment β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ Terminal 1: Backend β”‚
β”‚ $ cd backend β”‚
β”‚ $ source .venv/bin/activate β”‚
β”‚ $ uvicorn main:app --reload --port 8000 β”‚
β”‚ β”‚
β”‚ Terminal 2: Frontend β”‚
β”‚ $ cd frontend β”‚
β”‚ $ npm run dev β”‚
β”‚ β†’ Vite dev server on http://localhost:5173 β”‚
β”‚ β”‚
β”‚ Database: SQLite (auto-created) β”‚
β”‚ Email: Console fallback (no SMTP needed) β”‚
β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
### 9.2 Production Recommendations
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Production Architecture β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Nginx │───▢│ Uvicorn │───▢│ PostgreSQL β”‚ β”‚
β”‚ β”‚ (Reverse β”‚ β”‚ (Gunicorn β”‚ β”‚ (or MySQL) β”‚ β”‚
β”‚ β”‚ Proxy) β”‚ β”‚ Workers) β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ Port 443 β”‚ β”‚ Port 8000 β”‚ β”‚ Port 5432 β”‚ β”‚
β”‚ β”‚ HTTPS β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ β”‚ β”‚ Redis β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ (Cache + │◀───────────── β”‚
β”‚ β”‚ β”‚ Rate β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ Limiting) β”‚ β”‚ β”‚
β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
β”‚ └───────────▢│ Static β”‚ β”‚ β”‚
β”‚ β”‚ Files β”‚ β”‚ β”‚
β”‚ β”‚ (React β”‚ β”‚ β”‚
β”‚ β”‚ Build) β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚
β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
## 10. Environment Configuration
| Variable | Development | Production | Purpose |
|----------|-------------|------------|---------|
| `SECRET_KEY` | `super_secret_dev_key...` | Strong random 256-bit key | JWT signing |
| `ALGORITHM` | `HS256` | `HS256` or `RS256` | JWT algorithm |
| `ACCESS_TOKEN_EXPIRE_MINUTES` | `30` | `15` | Shorter in prod |
| `REFRESH_TOKEN_EXPIRE_DAYS` | `7` | `7` | Refresh token TTL |
| `DATABASE_URL` | `sqlite:///./users.db` | `postgresql://...` | Database |
| `SMTP_SERVER` | `smtp.gmail.com` | `smtp.gmail.com` | Email server |
| `SMTP_PORT` | `587` | `587` | Email port |
| `SMTP_USER` | `user@gmail.com` | `noreply@domain.com` | Email sender |
| `SMTP_PASSWORD` | `app_password` | `app_password` | Email auth |
---
## 11. Future Improvements
### High Priority
- [ ] Add `.gitignore` (exclude `.env`, `users.db`, `__pycache__`, `node_modules`)
- [ ] Use `secrets` module for OTP generation (cryptographic randomness)
- [ ] Add per-account brute-force lockout (e.g., 5 failed attempts β†’ 15min lock)
- [ ] Move to PostgreSQL for production use
### Medium Priority
- [ ] Add Docker + docker-compose for containerized deployment
- [ ] Implement email rate limiting (prevent OTP spam)
- [ ] Add CSRF protection
- [ ] Add comprehensive unit and integration tests
- [ ] Implement account deletion with cascade (revoke all tokens)
### Low Priority
- [ ] Add OAuth2 social login (Google, GitHub)
- [ ] Implement 2FA (TOTP-based)
- [ ] Add admin dashboard for user management
- [ ] Implement audit logging
- [ ] Add API versioning (v1/, v2/)