JWT (JSON Web Tokens)

JWT (JSON Web Tokens)

Your web application has 20 servers behind a load balancer. A user logs in on server 3, and their next request lands on server 11. How does server 11 know this user is authenticated? With traditional sessions, server 3 stored the session in memory — server 11 has no idea who this user is. You could use a shared session store (Redis), but now every single API request requires a round-trip to Redis. At 100K requests per second, that’s 100K Redis lookups per second — just for authentication. JWTs solve this by encoding the authentication proof into the token itself, so any server can verify it locally with zero external calls.

The Problem: Stateful Sessions Don’t Scale

flowchart LR
    U(["User
session_id=abc"]) LB["Load Balancer
routes to ANY server"] U ==>|"request with session_id=abc"| LB LB --> S1["Server 1
✓ logged in here
sessions: {abc → user_42}"] LB ==> S2["Server 2
✗ no session abc
→ 401 Unauthorized"] LB --> S3["Server 3
✗ no session abc"] style S1 fill:#bfb,stroke:#2e7d32,color:#000 style S2 fill:#f99,stroke:#c62828,color:#000 style S3 fill:#eee,stroke:#999,color:#000

Three ways to fix this, each with trade-offs:

ApproachHow it worksProblem
Sticky sessionsLB routes same user to same serverServer crash loses all sessions; uneven load
Shared session storeAll servers read from Redis/MemcachedEvery request needs a DB round-trip; Redis is a SPOF
Self-contained token (JWT)Token carries the proof; any server validates locallyToken can’t be revoked before expiry (without extra infra)

JWT chooses the third approach: move the session data into the token itself, signed cryptographically so it can’t be tampered with. Any server with the signing key (or public key) can validate the token — no shared state, no external calls.

Test Your Understanding

Your team switches from a shared Redis session store to sticky sessions (the load balancer pins each user to one server) to dodge the Redis round-trip. What breaks during a routine rolling deploy?

Every user pinned to a restarting server is logged out. Sticky sessions keep the session in one server’s memory, so when a rolling deploy (or a crash, or a scale-down) removes that server, the sessions that lived only there vanish. You also get uneven load: long-lived users pile onto a few “hot” servers while freshly added ones sit idle, because existing users stay pinned.

Why JWT sidesteps this: the proof travels inside the token, so any server can serve any request. Deploys, crashes, and autoscaling become invisible to authenticated users.

Moving session data into a self-contained JWT removes the session-store lookup. What capability did the server-side session give you for free that you now have to design around?

Instant, server-side revocation. With a session store, logging a user out (or killing a stolen session) is a single delete — the very next request fails because the entry is gone. A JWT is validated locally with no lookup, so a still-valid-but-unwanted token keeps working until it expires.

Designing around it: short access-token TTLs (5–15 min) to shrink the exposure window, a revocable refresh token, and — only if you need an instant kill — a JTI blocklist checked at the gateway (which trades back some of the statelessness).