Sessions & Tokens
How proof-of-identity is carried across requests — server memory vs. self-contained tokens.
By the end of this lesson, choose between server-side sessions and tokens and understand their revocation trade-offs.
You authenticate once, then make hundreds of requests. Something must carry the fact 'this caller is subject X' forward. Two models dominate: server-side sessions (the server remembers; the client holds an opaque session ID) and tokens (the proof is self-contained in the client's possession, verified by signature).
First, see the whole system. Then we’ll open it up.
Stateful session vs. stateless token
- Server-side session: client sends an opaque id, the server looks it up in a store to find the subject.
- Self-contained token: client sends a signed token, the server verifies the signature to trust the subject without a lookup.
flowchart LR
subgraph sess [Server-side session]
c1[Client: session id] --> s1[Server store lookup] --> u1[Subject]
end
subgraph tok [Self-contained token]
c2[Client: signed token] --> v2[Verify signature] --> u2[Subject]
endSessions are stateful: the server (or a shared store like Redis) holds the truth. Revocation is trivial — delete the record. The cost is a lookup on every request and a shared store to scale.
Tokens are stateless: the server verifies a signature and trusts the contents. No lookup, scales horizontally with no shared state. The cost is revocation — a valid signed token is honored until it expires.
This is the core trade-off: sessions buy instant revocation at the price of shared state and per-request lookups. Tokens buy stateless scale at the price of weak revocation. Real systems often combine them: short-lived tokens (limits the revocation gap) plus a session/refresh store for the long-lived part.
This is where the abstraction starts leaking.
'JWTs are stateless so we don't need a database' — until you need to log someone out immediately, ban a compromised account, or revoke a leaked token. Then you rediscover state, usually as a denylist. Statelessness is a latency optimization, not a security property.
You issue 24-hour JWTs and store nothing server-side. A token leaks at hour 1. How do you revoke it? With pure stateless tokens, you can't — the attacker has 23 hours. What would you change?
Unrevocable leaked token
- Trigger
- Long-lived, self-contained tokens with no revocation mechanism.
- Symptom
- A stolen token remains valid until natural expiry, regardless of password resets.
- Blast radius
- Full access as the subject for the token's remaining lifetime.
- Mitigation
- Short access-token TTLs, refresh rotation, and a revocation/denylist for high-value tokens.
Deep dive: Token Replay
You must be able to force-logout any user within one second. Sessions or stateless JWTs?
Server-side sessions (or JWTs backed by a revocation store). Pure stateless JWTs cannot be revoked before expiry.