Intermediate18 min

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.

How deep?
How the pieces actually move.

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, the whole system

First, see the whole system. Then we’ll open it up.

Stateful session vs. stateless token

Stateful session vs. stateless token

  1. Server-side session: client sends an opaque id, the server looks it up in a store to find the subject.
  2. 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]
  end

Sessions 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.

State

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.

Abstraction leak

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.

Now break it

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.

A token that carries claims must be tamper-proof. How does a server trust a token it didn't store?

Next: JWT / JWS / JWE →