mirror of
https://github.com/duthaho/claudekit.git
synced 2026-06-10 12:14:57 +03:00
13 KiB
13 KiB
Authentication Flows Quick Reference
Decision Tree: Which Auth Method?
What are you building?
│
├─ Server-rendered web app (Next.js, Django, Rails)?
│ └─> SESSION-BASED AUTH
│ - HttpOnly cookies, server-side session store
│ - Simple, secure, well-understood
│
├─ SPA + API backend (same domain)?
│ └─> SESSION-BASED AUTH (still preferred)
│ - Cookies sent automatically, no JS token handling
│ - Or: JWT in HttpOnly cookie (not localStorage)
│
├─ SPA + API backend (different domain)?
│ └─> JWT with access + refresh tokens
│ - Access token: short-lived, in memory
│ - Refresh token: HttpOnly cookie
│
├─ Mobile app?
│ └─> JWT with access + refresh tokens
│ - Store refresh token in secure storage (Keychain/Keystore)
│ - Access token in memory
│
├─ Third-party API access?
│ └─> OAuth2 + API keys
│ - OAuth2 for user-delegated access
│ - API keys for server-to-server
│
├─ Machine-to-machine (service-to-service)?
│ └─> API KEYS or OAuth2 Client Credentials
│ - API key: simple, rotate regularly
│ - Client Credentials: when you need scoped access
│
└─ CLI tool?
└─> OAuth2 Device Code Flow or API key
JWT Access + Refresh Token Flow
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Client │ │ Auth │ │ API │
│ (SPA/ │ │ Server │ │ Server │
│ Mobile) │ │ │ │ │
└────┬──────┘ └────┬─────┘ └────┬─────┘
│ │ │
│ 1. POST /auth/login │ │
│ { email, password } │ │
│─────────────────────────────>│ │
│ │ │
│ 2. 200 OK │ │
│ { access_token (15min) } │ │
│ Set-Cookie: refresh_token │ │
│ (HttpOnly, Secure, 7d) │ │
│<─────────────────────────────│ │
│ │ │
│ 3. GET /api/data │ │
│ Authorization: Bearer <access_token> │
│─────────────────────────────────────────────────────────────>│
│ │ │
│ 4. 200 OK { data } │ │
│<─────────────────────────────────────────────────────────────│
│ │ │
│ ── access_token expires ── │ │
│ │ │
│ 5. GET /api/data │ │
│ Authorization: Bearer <expired_token> │
│─────────────────────────────────────────────────────────────>│
│ │ │
│ 6. 401 { code: "token_expired" } │
│<─────────────────────────────────────────────────────────────│
│ │ │
│ 7. POST /auth/refresh │ │
│ Cookie: refresh_token │ │
│─────────────────────────────>│ │
│ │ │
│ 8. 200 { new access_token } │ │
│ Set-Cookie: new refresh │ │
│<─────────────────────────────│ │
│ │ │
│ 9. Retry original request with new access_token │
│─────────────────────────────────────────────────────────────>│
JWT Best Practices
| Concern | Recommendation |
|---|---|
| Access token lifetime | 5-15 minutes |
| Refresh token lifetime | 7-30 days |
| Access token storage | Memory only (JS variable) |
| Refresh token storage | HttpOnly Secure cookie (web) or Keychain (mobile) |
| Token rotation | Issue new refresh token on each refresh |
| Revocation | Maintain server-side deny list for refresh tokens |
| Algorithm | RS256 (asymmetric) for distributed systems, HS256 for single server |
| Claims | Minimal: sub, exp, iat, roles/permissions |
OAuth2 Authorization Code + PKCE Flow
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Client │ │ Auth │ │ Resource │
│ (Browser)│ │ Provider│ │ Server │
└────┬──────┘ └────┬─────┘ └────┬──────┘
│ │ │
│ 1. Generate: │ │
│ code_verifier (random 43-128 chars) │
│ code_challenge = SHA256(code_verifier) │
│ │ │
│ 2. Redirect to: │ │
│ /authorize? │ │
│ response_type=code │
│ client_id=xxx │ │
│ redirect_uri=https://app/callback │
│ scope=openid profile │
│ state=random_csrf_token │
│ code_challenge=xxx │
│ code_challenge_method=S256 │
│────────────────────>│ │
│ │ │
│ 3. User logs in │ │
│ and consents │ │
│ │ │
│ 4. Redirect to: │ │
│ /callback?code=AUTH_CODE&state=xxx │
│<────────────────────│ │
│ │ │
│ 5. Verify state matches │
│ │ │
│ 6. POST /token │ │
│ { grant_type=authorization_code, │
│ code=AUTH_CODE, │ │
│ redirect_uri=...,│ │
│ code_verifier=ORIGINAL_VERIFIER } │
│────────────────────>│ │
│ │ │
│ 7. { access_token, │ │
│ refresh_token,│ │
│ id_token } │ │
│<────────────────────│ │
│ │ │
│ 8. GET /api/resource │
│ Authorization: Bearer <access_token> │
│───────────────────────────────────────────>│
PKCE Key Points
| Term | Purpose |
|---|---|
code_verifier |
Random string (43-128 chars), stored client-side |
code_challenge |
BASE64URL(SHA256(code_verifier)) sent in auth request |
state |
CSRF protection (random, verify on callback) |
| PKCE purpose | Prevents auth code interception (no client secret needed) |
Session-Based Auth Flow
┌──────────┐ ┌──────────────────┐
│ Browser │ │ Server │
│ │ │ (session store) │
└────┬──────┘ └────┬──────────────┘
│ │
│ 1. POST /login │
│ { email, password } │
│─────────────────────────────>│
│ │ 2. Verify credentials
│ │ 3. Create session in store
│ │ (Redis/DB/memory)
│ 4. Set-Cookie: │
│ session_id=abc123; │
│ HttpOnly; Secure; │
│ SameSite=Lax; Path=/ │
│<─────────────────────────────│
│ │
│ 5. GET /dashboard │
│ Cookie: session_id=abc123 │ (sent automatically)
│─────────────────────────────>│
│ │ 6. Lookup session abc123
│ │ 7. Attach user to request
│ 8. 200 OK │
│<─────────────────────────────│
│ │
│ 9. POST /logout │
│─────────────────────────────>│
│ │ 10. Delete session from store
│ 11. Clear cookie │
│<─────────────────────────────│
Session Cookie Settings
| Attribute | Value | Purpose |
|---|---|---|
HttpOnly |
Always | Prevent JS access (XSS protection) |
Secure |
Always in prod | Only send over HTTPS |
SameSite |
Lax (default) |
CSRF protection (allows top-level navigation) |
SameSite |
Strict |
Stronger CSRF (breaks external link login) |
Path |
/ |
Cookie scope |
Max-Age |
86400-2592000 | Session duration (1-30 days) |
Domain |
Omit or explicit | Cookie scope to domain |
Comparison: JWT vs Sessions vs API Keys
| Aspect | JWT | Sessions | API Keys |
|---|---|---|---|
| Stateless | Yes (no server lookup) | No (server-side store) | No (server-side lookup) |
| Revocation | Hard (needs deny list) | Easy (delete session) | Easy (delete key) |
| Scaling | Easy (no shared state) | Needs shared session store | Needs shared key store |
| Security | Token theft = access until expiry | Session theft = access until revoked | Key theft = access until rotated |
| Best for | Distributed APIs, mobile | Web apps, SSR | Service-to-service, CLI |
| CSRF risk | Low (if not in cookie) | Needs CSRF tokens | N/A (header-based) |
| XSS risk | High if in localStorage | Low (HttpOnly cookie) | Low (server-side only) |
API Key Best Practices
| Practice | Details |
|---|---|
| Prefix keys | sk_live_, pk_test_ (identify type/env) |
| Hash before storing | Store SHA256(key), never plaintext |
| Scope keys | Limit permissions per key |
| Set expiry | Auto-expire, require rotation |
| Rate limit per key | Prevent abuse |
| Transmit in header | Authorization: Bearer <key> or X-API-Key: <key> |
| Never in URL | Query params end up in logs and browser history |