Authentication: JWT vs Sessions
When to use JWTs vs server-side sessions — with real security tradeoffs and 2026 recommendations.
The "JWT vs sessions" debate is 10 years old and still misunderstood. The short answer: use server-side sessions for browser apps unless you have a specific reason not to. Here is why.
How each works
- Session — server stores state, browser holds an opaque cookie referencing that state. Lookup on every request.
- JWT — server issues a signed token containing the state. Browser sends it back. Server verifies the signature and trusts the payload.
The comparison table nobody puts in the docs
| Concern | Session | JWT |
|---|---|---|
| Revocation | Instant — delete row | Hard — needs a blocklist |
| Scale | Needs sticky session or shared store | Stateless |
| Payload size | Small cookie | Larger (headers grow) |
| Cross-service auth | Central check | Any service verifies |
| XSS impact | httpOnly cookie — safe | Usually LS/JS-accessible — leaked |
| CSRF risk | Yes — needs mitigation | Lower (with header transport) |
Rules of thumb (2026)
- Web app, single backend → session cookie,
httpOnly+Secure+SameSite=Lax. - Mobile app talking to your own API → short-lived JWT access token + rotating refresh token stored in the OS keychain.
- Microservices or federated auth → JWT for service-to-service, session for the user-facing edge.
- Public API for third parties → OAuth 2.1 with PKCE, JWT access tokens.
The three biggest JWT mistakes
- Storing JWTs in
localStorage. XSS = complete account takeover. - Using long-lived JWTs (days or weeks) with no refresh rotation.
- Trusting the
algheader — force a specific algorithm on the verify side (noneattacks still exist in the wild).
Don't pick JWT because it's fashionable. Pick the mechanism whose failure mode you can live with.