JWT vs Session Tokens
Sessions keep the truth server-side: an opaque 16–32 byte token indexes a store you control, so revocation is instant and cheap. JWTs carry the truth in the token itself — signed, stateless, verified anywhere — but revocation means waiting out the expiry. Use sessions for single-app logins; JWTs when many services must verify identity without a shared store.
Die folgende Anleitung ist nur auf Englisch verfügbar.
JWT vs Session Tokens explained
Both designs solve the same problem: HTTP requests arrive without memory, so each request needs something that says “this is the same person who logged in”. A classic session hands the client an opaque token — a random string pointing at server-side state. A JWT (RFC 7519) hands the client the state itself: a signed bundle of claims the server verifies without looking anything up. One stores truth on the server; the other notarises it and sends it along.
That difference — where the truth lives — cascades into every trade-off here. A JWT verifies with a signature check, so any service holding the key can authenticate a request without a shared store; the price is that the token stays valid until its exp claim, so “log out now” and “ban this user now” have no natural implementation. A session token is worthless without its store, so revocation is a delete — but every verifying service must reach that store.
Neither side is winning, and mature systems routinely run both — opaque session cookies for the human-facing app, short-lived JWTs between services. The sections below compare revocation, storage, size and attack surface; the decoder linked throughout lets you inspect real tokens with nothing uploaded.
Before trusting any token in production, unfold one with the JWT decoder — it decodes header and payload locally and never asks for a key.
For a segment-by-segment anatomy, the JWT structure guide walks header, payload and signature with real examples.
Two shapes, two philosophies
A server session is a pointer. The token — 16 to 32 random bytes, usually set as a cookie — carries no meaning; all meaning lives in the store: Redis, a database, even process memory. That indirection is the feature. The record can hold anything, change anything or vanish, and clients never notice, holding only a pointer.
A JWT is a statement. Three base64url segments — header, payload, signature — carry the claims: sub for the user, iss for the issuer, exp for expiry, plus custom claims. The signature (HMAC with a shared secret, or RSA/ECDSA with a key pair) proves the statement is intact and came from a key-holder. Verifying needs no lookup; trusting needs only the key.
Revocation: the trade-off that decides most projects
With sessions, “sign out” and “ban user” are store operations: delete the record, and the next request fails. With JWTs, the token stays cryptographically valid until exp no matter what the issuing server now wishes — the point of statelessness is that verification never checks back. The mitigations are well known and all reintroduce state: short expiry with refresh-token rotation, jti denylists, or a version claim bumped on logout. Each rebuilds a slice of the store you gave up.
The honest framing: sessions make revocation free but charge a store lookup on every request; JWTs make it a design decision you pay for at logout time. If “log out everywhere, immediately” is a requirement, sessions or tightly managed rotation are in your future.
Storage and attack surface: cookies, localStorage, XSS and CSRF
Where the token lives matters as much as what it is. A JWT parked in localStorage is readable by every script on the page, so one XSS flaw exfiltrates a bearer credential valid until expiry — with no server-side way to revoke it. An opaque token in an HttpOnly, Secure, SameSite cookie is invisible to JavaScript, which caps the blast radius of XSS; the cost is CSRF exposure — the browser attaches the cookie automatically — mitigated with SameSite and CSRF tokens.
JWTs can ride in cookies too (and often should), with the same CSRF caveats; an Authorization header dodges CSRF but lands the token back in JavaScript's reach. No storage arrangement is safe against XSS — only arrangements that limit what the attacker can steal.
Size, and what a JWT actually reveals
A typical login JWT measures 800 bytes or more with a few claims, and every request repeats it — while cookies top out around 4 KB per domain. An opaque session token stays 16–32 bytes regardless. At scale the difference shows up in headers, proxies and logs.
The payload is base64url — encoding, not encryption — so anyone holding the token can read every claim, PII and permissions included. JWE exists for encrypted tokens and is almost never used. Paste a real token into the decoder below: header and payload unfold in your browser, the signature displayed but never verified — verification needs the secret key, which the tool never asks for.
| Aspect | Server session | JWT (RFC 7519) |
|---|---|---|
| Where truth lives | Server-side store | Inside the signed token |
| Revocation | Instant — delete the record | At exp, or via added state |
| Token size | 16–32 opaque bytes | ~800 B+ with typical claims |
| Verification cost | Store lookup per request | Signature check, no lookup |
| Multi-service auth | Shared session store required | Any service holding the key |
| Expiry | Server-side TTL, mutable | exp claim, fixed at issue |
| Browser storage | HttpOnly + SameSite cookie | Cookie, or localStorage (XSS risk) |
When to pick which
Pick sessions when one application serves the login: server-rendered sites, admin panels, anything where instant logout and device management are worth one Redis lookup. Pick JWTs when verification must happen in many places — microservices, mobile apps, cross-team services — and a shared session store for all of them is the heavier cost.
The guidance reverses cleanly. The moment you build a denylist or rotation service to make JWTs revocable, ask whether a session store snuck back in; the moment a session store bottlenecks a dozen services, ask whether short-lived JWTs between them would be lighter. Hybrids — an opaque cookie for the browser, JWTs for service-to-service — are not a compromise; they are the normal end state.
Frequently asked questions
Can I decode a JWT here without uploading it or sending it anywhere?
Yes. The decoder runs entirely in your browser: header and payload are plain base64url, so they unfold locally with no request leaving the tab — the site's Content-Security-Policy blocks outbound calls. The signature is displayed for inspection but never verified: verification requires the signing key, which the tool never asks for.
Is a JWT encrypted?
No. RFC 7519 defines a signed token: the payload is base64url — readable by anyone holding it — and the signature only proves who issued it and that it was not altered. Encryption is a separate profile (JWE) real systems rarely use. Treat every claim as public: identifiers and roles are fine; secrets and PII are not.
How do I revoke a JWT immediately?
You cannot with the token alone — that is the statelessness trade. Real systems add state back: short exp windows with refresh-token rotation so stolen tokens die fast, a denylist keyed on the jti claim, or a token-version claim bumped on logout. All three are a session store with extra steps.
Are HttpOnly cookies safer than localStorage for tokens?
Against XSS, yes. localStorage is readable by every script on the page, so one injection steals a bearer token valid until expiry; an HttpOnly cookie is invisible to JavaScript, so the same injection cannot lift it. The cookie's cost is CSRF, handled with SameSite and CSRF tokens. HttpOnly does not defeat XSS — it removes the token from the loot.
Why do microservices prefer JWTs over sessions?
Because verification becomes local. With RS256, each service holds the public key and validates tokens with no call to a shared session store; a new service boots with a key, not an integration. Opaque sessions put every service at the mercy of one store's availability. That independence is what statelessness buys — revocation is the bill.
How big can a JWT get before it is a problem?
Watch cookies first: browsers cap them around 4 KB per domain, and a claims-heavy JWT can approach that and break requests outright. Even below the cap, an ~800-byte token rides every request, while an opaque session token stays 16–32 bytes regardless. Keep claims lean: identity and expiry, not profile data.
Which related tools should I use next?
- JWT DecoderDecode a JSON Web Token and see what every claim means.Open
- JWT StructurePlain-English guideOpen
- How Does Base64 WorkPlain-English guideOpen
- Encoding ToolsBase64, URL encoding, hashing and token inspection.Open
- UUID vs NanoIDHead-to-head comparisonOpen
- JSON FormatterIndent, sort keys and strip comments with configurable output.Open