Stateless JWT vs stateful sessions — the real trade-offs, performance numbers, and which is right for your architecture.
| Factor | Session Cookies | JWT |
|---|---|---|
| Server storage required | Yes (DB/Redis) | No |
| Instant revocation | Yes (delete session) | Hard (need blocklist) |
| Multi-server scaling | Hard (shared session DB) | Easy (stateless) |
| Mobile app support | Harder (cookie issues) | Natural (Authorization header) |
| Microservices | Complex (shared session) | Natural (self-contained) |
| XSS vulnerability | Lower (HttpOnly cookie) | Higher (if in localStorage) |
| CSRF vulnerability | Higher | Lower (not sent automatically) |
The biggest JWT limitation: you cannot invalidate a token before it expires. If a user's account is compromised, you cannot "log them out" server-side — the token remains valid until expiry. Solutions: (1) very short expiry times (15 minutes) with refresh tokens, (2) maintain a token blocklist in Redis, (3) use sessions for security-critical flows.