Jul 30, 2026
5 min read
HTTP is stateless — the server forgets you between requests. Classic web apps solved this with sessions: the server stores "user 42 is logged in" in its memory or database and hands the browser a session ID cookie. That works, but the server must store and look up state for every user on every request, and sharing that state across multiple servers or services gets awkward.
A JSON Web Token flips the model: instead of the server remembering who you are, you carry a signed note that proves it. The server checks the signature and trusts the contents — no lookup, no shared session store. That self-contained property is why JWTs dominate modern APIs, single-page apps, and microservice authentication.
A JWT is three Base64url-encoded segments joined by dots — header.payload.signature:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
1. Header — metadata: which signing algorithm is used.
{ "alg": "HS256", "typ": "JWT" }
2. Payload — the claims: statements about the user and the token itself. Standard claims have three-letter names: sub (subject — the user ID), iat (issued at), exp (expiry), iss (issuer). Apps add their own: roles, email, permissions.
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
3. Signature — the security. The server computes a cryptographic signature over the first two parts using a secret key: HMAC-SHA256(header + "." + payload, secret). Change a single character of the payload and the signature no longer matches.
Paste the token above into the free JWT Decoder and watch it split into these parts — decoding happens entirely in your browser.
The header and payload are encoded, not encrypted. Base64url is a reversible text format — anyone holding the token can read every claim inside it, no key required. (If that distinction is fuzzy, our Base64 explainer covers exactly why encoding is not encryption.)
So what does the signature give you? Integrity, not secrecy. A JWT is like a passport: anyone can open it and read your details, but the tamper-proof seal means nobody can alter it without detection. The rules that follow:
sub, exp, roles), signs it with its secret key, and returns the JWT.Authorization: Bearer <token>.exp. Match and unexpired → the request is authenticated. No database lookup needed.exp, the token is rejected and the client must log in again or use a refresh token.Step 4 is the magic and the trade-off in one: verification is pure computation, which scales beautifully — but it also means the server cannot easily "un-issue" a token before it expires.
| Session cookies | JWT | |
|---|---|---|
| Server-side state | Required (store + lookup) | None — token is self-contained |
| Scales across services | Needs a shared session store | Naturally (any service with the key verifies) |
| Instant revocation (logout, ban) | Trivial — delete the session | Hard — token stays valid until exp |
| Payload readable by holder | No (ID is opaque) | Yes — never store secrets |
Neither is universally better. Traditional server-rendered apps are often simpler and safer with sessions; APIs and microservices usually benefit from JWTs. The revocation weakness is typically mitigated with short-lived access tokens (minutes) paired with longer-lived refresh tokens.
alg header. Historic libraries accepted "alg": "none" — an unsigned token — letting attackers forge anything. Modern libraries reject this, but the lesson stands: the server must dictate the allowed algorithm, never the token.exp is a permanent skeleton key.localStorage carelessly. Any XSS vulnerability hands the attacker every user's token. HttpOnly cookies or in-memory storage reduce that blast radius.The fastest way to make JWTs concrete: grab a token from any tutorial (or the example above), drop it into the JWT Decoder, and inspect the claims. Then change one payload character and notice the decoded JSON changes while the signature stays the same — which is precisely what a verifying server catches. For the signing side, the Hash Generator lets you experiment with the SHA-256 hashing that HS256 is built on.
Building authentication for a web development assignment — token issuing, middleware verification, refresh flows — and stuck on where the pieces go? The programming help service at EduSupport pairs you with developers who build auth systems for a living, available around the clock.
Our expert team is available 24/7 for assignments, projects, and exam prep.