JWT vs Session Cookies
A detailed comparison of features, privacy, and developer experience.
Last reviewed: 2026-05-17
Executive Summary
For most web apps, session cookies are simpler, more secure, and easier to revoke. JWTs win for stateless cross-service auth and short-lived API tokens, not for browser sessions.
JWT
JSON Web Tokens, signed (or encrypted) tokens carrying claims. Stateless on the server: the token itself is the credential, validated by signature alone.
Session Cookies
Server-issued opaque session IDs stored in an HttpOnly cookie. The server keeps the session state (in Redis, Postgres, memory); the cookie is just a lookup key.
Editor's Verdict
JWTs got over-prescribed for a decade. For a typical web app where users log in via a browser, session cookies (HttpOnly, Secure, SameSite=Lax) are the right call almost always: revocation is instant (delete the row), the cookie can't be read by JS, and you don't carry user data in the URL or local storage. JWTs shine in two specific cases: (1) cross-service auth where the auth server and the resource server are separate teams and you don't want a network call to validate every request, and (2) short-lived API tokens (15 min) issued to a service or a mobile app. The big JWT footgun is revocation, once issued, a JWT is valid until its `exp` claim, full stop, unless you maintain a blocklist (which gives back the statefulness you were trying to avoid).
What we ran
A decoded JWT fixture carried `exp` and `sub` with no server lookup. A session cookie workflow needs a store to revoke. We could not revoke the JWT without a denylist. Use sessions when logout must be immediate; JWTs when services cannot share a session DB.
🎫When to use JWT
- Cross-service auth where validating means signature check, no DB lookup
- Short-lived API tokens (≤15 min) for service clients or mobile apps
- OIDC ID tokens, that's literally what they're for
🍪When to use Session Cookies
- Browser-based user sessions (almost always the right answer)
- You need instant revocation (logout-everywhere, ban a user, rotate credentials)
- You want HttpOnly cookies so XSS can't steal the credential
| Feature | JWT | Session Cookies |
|---|---|---|
| Server state | Stateless | Stateful (session store) |
| Revocation | Hard (needs blocklist) | Instant (DELETE row) |
| XSS protection | Token usually in JS-readable storage | HttpOnly cookie |
| CSRF protection | Bearer header → safe | Need CSRF token / SameSite |
| Token size on wire | 300–1500 bytes per request | 30–50 byte cookie |
| Cross-domain | Easy (header) | Needs CORS + SameSite=None |
| Carries user data | Yes (in claims) | No (server-side lookup) |
Key Takeaways
- Session cookies: server-side state, easy to revoke, simple, secure by default with httpOnly + Secure + SameSite.
- JWTs: stateless, embeddable across services, but revocation requires either short TTL or a deny-list.
- For monolithic web apps: sessions. For distributed services or mobile/SPA + multiple backends: JWT.
- JWT in localStorage is XSS-readable; httpOnly cookies are the safer carrier for either model.
- 'Stateless' is a feature for scaling reads, a liability for security ops, short TTL + refresh tokens are the compromise.
Common Mistakes
- Storing JWTs in localStorage, XSS-readable; any injected script can steal the token.
- Setting long JWT TTLs (24h+) without a revocation strategy, stolen tokens stay valid until expiry.
- Treating JWTs as encrypted, they're signed, not encrypted; the payload is base64-readable.
- Putting sensitive data in JWT claims, they travel over the wire and can be cached client-side.
Frequently Asked Questions
Where should I store a JWT in the browser?+
Honest answer: there's no fully safe place. localStorage is XSS-vulnerable, cookies need CSRF protection, and in-memory means re-auth on every reload. This is the core reason session cookies are usually the better answer for browser apps.
What about refresh tokens?+
A common pattern: short-lived access JWT (5–15 min) + long-lived refresh token (stored as HttpOnly cookie). The refresh token is server-side trackable, the access token is stateless. This is essentially reinventing sessions on top of JWTs, fine, but be honest about it.
How we tested this
We evaluated both JWT and Session Cookies in real developer workflows to build this comparison. Our assessment covers feature parity, privacy posture, developer experience, and ecosystem maturity.
Why these tools are worth your time
Privacy-respecting picks
We prefer tools that run locally or are explicit about what they send to the cloud.
Daily-driver tested
Recommendations come from real developer workflows, not marketing pages.
No vendor lock-in advice
We surface the trade-offs so you can switch later without rewriting your stack.