14 KiB
14 KiB
Authentication Flow Diagrams
Cookie Isolation Architecture
┌─────────────────────────────────────────────────────────────┐
│ Browser │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Admin Area │ │ Vendor Area │ │
│ │ /admin/* │ │ /vendor/* │ │
│ │ │ │ │ │
│ │ 🍪 admin_token │ │ 🍪 vendor_token │ │
│ │ Path: /admin │ │ Path: /vendor │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │ │ │
│ ├───────────────────────────┤ │
│ │ ❌ No Cookie Mixing │ │
│ │ │ │
└───────────┼───────────────────────────┼──────────────────────┘
│ │
▼ ▼
┌───────────────────────┐ ┌───────────────────────┐
│ Admin Backend │ │ Vendor Backend │
│ /admin/* │ │ /vendor/* │
│ │ │ │
│ ✅ admin_token │ │ ✅ vendor_token │
│ ❌ vendor_token │ │ ❌ admin_token │
└───────────────────────┘ └───────────────────────┘
Login Flow - Admin
┌──────────┐
│ Browser │
└──────────┘
│
│ POST /api/v1/admin/auth/login
│ { username, password }
▼
┌─────────────────────────┐
│ Admin Auth Endpoint │
│ │
│ 1. Validate credentials│
│ 2. Check role == admin │
│ 3. Generate JWT │
└─────────────────────────┘
│
│ Set-Cookie: admin_token=<JWT>; Path=/admin; HttpOnly; SameSite=Lax
│ Response: { access_token, user }
▼
┌──────────┐
│ Browser │──────────────────────────────────────┐
│ │ │
│ 🍪 admin_token (Path=/admin) │
│ 💾 localStorage.access_token │
└──────────┘ │
│ │
├── Navigate to /admin/dashboard ────────────┤
│ (Cookie sent automatically) │
│ │
└── API call to /api/v1/admin/vendors ───────┤
(Authorization: Bearer <token>) │
│
┌──────────────▼──────────────┐
│ get_current_admin_user() │
│ │
│ 1. Check Auth header │
│ 2. Check admin_token cookie │
│ 3. Validate JWT │
│ 4. Verify role == admin │
│ ✅ Return User │
└──────────────────────────────┘
Login Flow - Vendor
┌──────────┐
│ Browser │
└──────────┘
│
│ POST /api/v1/vendor/auth/login
│ { username, password }
▼
┌─────────────────────────┐
│ Vendor Auth Endpoint │
│ │
│ 1. Validate credentials│
│ 2. Block if admin │──────> ❌ "Admins cannot access vendor portal"
│ 3. Check vendor access │
│ 4. Generate JWT │
└─────────────────────────┘
│
│ Set-Cookie: vendor_token=<JWT>; Path=/vendor; HttpOnly; SameSite=Lax
│ Response: { access_token, user, vendor }
▼
┌──────────┐
│ Browser │──────────────────────────────────────┐
│ │ │
│ 🍪 vendor_token (Path=/vendor) │
│ 💾 localStorage.access_token │
└──────────┘ │
│ │
├── Navigate to /vendor/ACME/dashboard ──────┤
│ (Cookie sent automatically) │
│ │
└── API call to /api/v1/vendor/ACME/products ┤
(Authorization: Bearer <token>) │
│
┌──────────────▼──────────────┐
│ get_current_vendor_user() │
│ │
│ 1. Check Auth header │
│ 2. Check vendor_token cookie│
│ 3. Validate JWT │
│ 4. Block if admin │──> ❌ Error
│ 5. Verify vendor access │
│ ✅ Return User │
└──────────────────────────────┘
Security Boundary Enforcement
┌─────────────────────┐
│ Request Comes In │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ What's the path? │
└──────────┬──────────┘
│
┌───────────────┼───────────────┐
│ │ │
Starts with Starts with Starts with
/admin/* /vendor/* /api/*
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Check for: │ │ Check for: │ │ Check for: │
│ - admin_token │ │ - vendor_token │ │ - Authorization │
│ cookie │ │ cookie │ │ header │
│ - OR Auth header │ │ - OR Auth header │ │ (required) │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Validate: │ │ Validate: │ │ Validate: │
│ - JWT valid │ │ - JWT valid │ │ - JWT valid │
│ - User active │ │ - User active │ │ - User active │
│ - Role = admin │ │ - Role != admin │ │ - Any role │
│ │ │ - Has vendor │ │ (depends on │
│ │ │ access │ │ endpoint) │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │
▼ ▼ ▼
✅ Allowed ✅ Allowed ✅ Allowed
Cross-Context Prevention
❌ What's Blocked
Admin trying to access vendor route:
┌──────────────────────────────────────────┐
│ User: admin@example.com (role: admin) │
│ Token: Valid JWT with admin role │
│ Request: GET /vendor/ACME/dashboard │
└──────────────────────────────────────────┘
│
▼
┌───────────────────────┐
│ get_current_vendor_ │
│ from_cookie_or_header │
└───────────┬───────────┘
│
▼
Check: role == "admin"?
│
▼ Yes
❌ InsufficientPermissionsException
"Vendor access only - admins cannot use vendor portal"
Vendor trying to access admin route:
┌──────────────────────────────────────────┐
│ User: vendor@acme.com (role: vendor) │
│ Token: Valid JWT with vendor role │
│ Request: GET /admin/dashboard │
└──────────────────────────────────────────┘
│
▼
┌───────────────────────┐
│ get_current_admin_ │
│ from_cookie_or_header │
└───────────┬───────────┘
│
▼
Check: role == "admin"?
│
▼ No
❌ AdminRequiredException
"Admin privileges required"
Admin cookie sent to vendor route:
┌──────────────────────────────────────────┐
│ Cookie: admin_token=<JWT> (Path=/admin) │
│ Request: GET /vendor/ACME/dashboard │
└──────────────────────────────────────────┘
│
▼
Browser checks cookie path
│
▼
Path /vendor does NOT match /admin
│
▼
❌ Cookie NOT sent
Request has no authentication
│
▼
❌ InvalidTokenException
"Vendor authentication required"
Cookie Lifecycle
LOGIN
│
├── Server generates JWT
├── Server sets cookie:
│ • Name: admin_token or vendor_token
│ • Value: JWT
│ • Path: /admin or /vendor
│ • HttpOnly: true
│ • Secure: true (production)
│ • SameSite: Lax
│ • Max-Age: matches JWT expiry
│
└── Server returns JWT in response body
└── Client stores in localStorage (optional)
PAGE NAVIGATION
│
├── Browser automatically includes cookie
│ if path matches
│
├── Server reads cookie
├── Server validates JWT
└── Server returns page or 401
API CALL
│
├── Client reads token from localStorage
├── Client adds Authorization header
│ Authorization: Bearer <JWT>
│
├── Server reads header
├── Server validates JWT
└── Server returns data or 401
LOGOUT
│
├── Client calls logout endpoint
├── Server clears cookie:
│ response.delete_cookie(name, path)
│
└── Client clears localStorage
localStorage.removeItem('access_token')
Key Takeaways
- Cookie Path Isolation = No cross-context cookies
- Role Checking = Admins blocked from vendor routes
- Dual Auth Support = Cookies for pages, headers for API
- Security First = HttpOnly, Secure, SameSite protection
- Clear Boundaries = Each context is completely isolated