Sessions vs JWT

intermediate jwt sessions cookies authentication tokens

After someone logs in, how does the server remember them on the next request? HTTP is stateless — every request arrives with no memory of the last one. Two big approaches: server-side sessions and JWTs. This is a super common interview topic.

In simple language — the server remembers who’s logged in, and the browser just carries a ticket stub.

On login, the server creates a session (a record in memory, Redis, or a DB), generates a random session ID, and sends it back in a cookie. On every later request, the browser auto-sends that cookie, the server looks up the session, and knows who we are.

Set-Cookie: sid=8f3a...random...; HttpOnly; Secure; SameSite=Lax

The session ID is meaningless on its own — it’s just a lookup key. All the real data (user id, roles) lives on the server.

JWT — the token carries the state

A JWT (JSON Web Token) flips it around. Instead of storing state on the server, we pack the user info into the token itself, sign it, and hand it over. The server keeps nothing. That’s what “stateless” means.

On the next request, the client sends the token back (usually Authorization: Bearer ...). The server just verifies the signature — no database lookup needed. If the signature checks out, we trust the claims inside.

Think of it like the difference between a coat-check ticket (session ID — number means nothing without the server’s records) and a signed, tamper-proof concert wristband (JWT — everything’s printed right on it).

Session
state on SERVER
cookie: sid=8f3a
↓ every request
server looks up session store
✓ easy to revoke
✗ needs a lookup / shared store
JWT
state in the TOKEN
header: Bearer eyJ...
↓ every request
server just verifies signature
✓ no lookup, scales flat
✗ hard to revoke early

JWT structure — three parts, dot-separated

A JWT is just three Base64URL chunks glued with dots: header.payload.signature.

HEADER  algorithm + type  { "alg": "HS256", "typ": "JWT" }
PAYLOAD  the claims  { "sub": "7", "role": "admin", "exp": 1732 }
SIGNATURE  HMAC(header + "." + payload, secret)
final token:  eyJhbGc.eyJzdWI.4pWn8...

Two things people always get wrong: the payload is Base64, not encrypted — anyone can decode and read it, so never put secrets in there. And the signature doesn’t hide anything; it just proves the token wasn’t tampered with, because only the server knows the signing secret.

The revocation problem

Here’s the JWT catch interviewers dig into. Because the server keeps no state, it can’t easily un-issue a token. If a token is stolen, or a user is banned, that JWT stays valid until it expires on its own. There’s no session to delete.

Workarounds:

  • Short-lived access tokens (5–15 min) + a long-lived refresh token to get new ones. Small blast radius.
  • A denylist of revoked token IDs — but now we’re keeping server state again, which defeats the “stateless” selling point.

Sessions don’t have this problem: delete the session row and the user is instantly out.

Where to store the token

This is the security part, and it’s all about picking your poison.

  • localStorage — easy, but readable by any JavaScript on the page. One XSS (cross-site scripting — attacker runs JS in our page) and the token is stolen.
  • Cookie with HttpOnly — JS can’t read it, so XSS can’t grab it. But cookies auto-send on every request, which opens CSRF (cross-site request forgery — another site tricks the browser into sending our cookie). We defend that with the SameSite attribute and CSRF tokens.

So the trade-off in one line: localStorage dodges CSRF but is exposed to XSS; HttpOnly cookies dodge XSS but need CSRF protection. The common recommendation leans toward HttpOnly; Secure; SameSite cookies.

Interview soundbite

Sessions store state on the server and send a random session ID in a cookie — easy to revoke, needs a lookup. JWTs are stateless: signed claims live in the token (header.payload.signature, Base64 not encrypted), so the server just verifies the signature — scales flat but is hard to revoke before expiry. Fix revocation with short access tokens plus refresh tokens. Store tokens in HttpOnly cookies to dodge XSS, then add SameSite/CSRF tokens for CSRF.