1---2name: jwt3description: Implement secure JWT authentication with proper validation, token lifecycle, and key management.4---5
6## Quick Reference
7
8| Topic | File |
9|-------|------|
10| Algorithm selection | `algorithms.md` |
11| Token lifecycle | `lifecycle.md` |
12| Validation checklist | `validation.md` |
13| Common attacks | `attacks.md` |
14
15## Security Fundamentals
16
17- JWTs are signed, not encrypted—anyone can decode and read the payload; never store secrets in it
18- Always verify signature before trusting claims—decode without verify is useless for auth
19- The `alg: none` attack: reject tokens with algorithm "none"—some libraries accepted unsigned tokens
20- Use strong secrets: HS256 needs 256+ bit key; short secrets are brute-forceable
21
22## Algorithm Choice
23
24- HS256 (HMAC): symmetric, same key signs and verifies—good for single service
25- RS256 (RSA): asymmetric, private key signs, public verifies—good for distributed systems
26- ES256 (ECDSA): smaller signatures than RSA, same security—preferred for size-sensitive cases
27- Never let the token dictate algorithm—verify against expected algorithm server-side
28
29## Required Claims
30
31- `exp` (expiration): always set and verify—tokens without expiry live forever
32- `iat` (issued at): when token was created—useful for invalidation policies
33- `nbf` (not before): token not valid until this time—for scheduled access
34- Clock skew: allow 30-60 seconds leeway when verifying time claims
35
36## Audience & Issuer
37
38- `iss` (issuer): who created the token—verify to prevent cross-service token theft
39- `aud` (audience): intended recipient—API should reject tokens for other audiences
40- `sub` (subject): who the token represents—typically user ID
41- Token confusion attack: without aud/iss validation, token for Service A works on Service B
42
43## Token Lifecycle
44
45- Access tokens: short-lived (5-15 min)—limits damage if stolen
46- Refresh tokens: longer-lived, stored securely—used only to get new access tokens
47- Refresh token rotation: issue new refresh token on each use, invalidate old one
48- Revocation is hard—JWTs are stateless; use short expiry + refresh, or maintain blacklist
49
50## Storage
51
52- httpOnly cookie: immune to XSS, but needs CSRF protection
53- localStorage: vulnerable to XSS, but simpler for SPAs
54- Memory only: most secure, but lost on page refresh
55- Never store in URL parameters—visible in logs, history, referrer headers
56
57## Validation Checklist
58
59- Verify signature with correct algorithm (don't trust header's alg)
60- Check `exp` is in future (with clock skew tolerance)
61- Check `iat` is not unreasonably old (optional policy)
62- Verify `iss` matches expected issuer
63- Verify `aud` includes your service
64- Check `nbf` if present
65
66## Common Mistakes
67
68- Storing sensitive data in payload—it's just base64, not encrypted
69- Huge payloads—JWTs go in headers; many servers limit header size to 8KB
70- No expiration—indefinite tokens are security nightmares
71- Same secret across environments—dev tokens work in production
72- Logging tokens—they're credentials; treat as passwords
73
74## Key Rotation
75
76- Use `kid` (key ID) claim to identify which key signed the token
77- JWKS (JSON Web Key Set) endpoint for public key distribution
78- Overlap period: accept old key while transitioning to new
79- After rotation, old tokens still valid until they expire—plan accordingly
80
81## Implementation
82
83- Use established libraries—don't implement JWT parsing yourself
84- Libraries: `jsonwebtoken` (Node), `PyJWT` (Python), `java-jwt` (Java), `golang-jwt` (Go)
85- Middleware should reject invalid tokens early—before any business logic