Traditional logins made the server remember you — a session stored in memory or a database, looked up on every request. A JWT (JSON Web Token) flips that: instead of the server remembering, the client carries a small, signed proof of who it is on every single request. The server verifies the proof with math, not a lookup.
What’s actually inside a JWT
A JWT is just three base64url-encoded chunks joined by dots: header.payload.signature. Paste any JWT into jwt.io and you can read the first two parts instantly — they are encoded, not encrypted.
- Header — which algorithm signed this token, e.g.
{ "alg": "HS256", "typ": "JWT" }. - Payload — the actual claims:
{ "sub": "user_42", "role": "admin", "exp": 1735689600 }. Anyone who intercepts the token can read this. - Signature —
HMACSHA256(header + "." + payload, secretKey). Change one character of the payload and the signature no longer matches — that’s how tampering gets caught.
The full round trip, request by request
Here’s the entire lifecycle: one login, then one authenticated request. Click any arrow to jump to that moment, or let it play.
The user submits credentials once, over HTTPS. This is the only time a password is ever sent.
Why “no database lookup” is the whole point
After login, the server never queries anything to check who you are — it just re-verifies the signature using a secret key only it knows. That means any server behind a load balancer can validate the same token without sharing session state, which is exactly why JWTs are the default for APIs and microservices that need to scale horizontally.
Where should the client keep the token?
localStorage
- Easy to read and attach manually in JS
- Survives tab refreshes and browser restarts
- Readable by any script on the page — a classic XSS risk
- Never sent automatically, so no CSRF exposure
httpOnly cookie
- Invisible to JavaScript — immune to XSS theft
- Sent automatically by the browser on every request
- Needs CSRF protection since it's sent automatically
- Requires same-site / domain configuration to scope it
15 min – 1 hr
Typical access token life
HS256 / RS256
Common algorithms
~100–400 bytes
Per-request overhead
JWT vs. sessions, in one line
JWTs trade a database lookup for a math check — great for stateless, distributed APIs, but it means you can’t instantly revoke a single token (it’s valid until it expires, full stop). Sessions make the opposite trade. That comparison is exactly what the next post covers.