All Writing
Auth7 min read

How JWT actually works.

JSON Web Tokens, traced through a real login and a real API call — and why the server never has to remember you.

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.

The one-sentence version
A JWT is a tamper-proof claim — “I am user 42, and the server agreed to this as of 10 minutes ago” — that the client presents instead of making the server remember it.

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.
Common mistake
The payload is readable by anyone with the token — it is signed, not encrypted. Never put passwords, secrets, or anything sensitive in a JWT payload, even if “only the server reads it.” The client (and anyone on the network) can decode it in one line of code.

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.

Client
Server
Step 1 of 8

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

In practice
Most production setups pair a short-lived JWT access token with a longer-lived refresh token stored in an httpOnly cookie — so a stolen access token expires fast, while the user doesn’t have to re-login every 15 minutes.

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.