JWT Explained: How JSON Web Tokens Work
JWT tokens are in every Authorization header, but most developers never look inside them. Learn the header.payload.signature structure, common claims, signing algorithms, and the security mistakes to avoid.
What Is a JWT?
A JSON Web Token (JWT, pronounced “jot”) is a compact, URL-safe token used to securely transmit information between two parties. It is most commonly used for authentication — after a user logs in, the server issues a JWT which the client sends with every subsequent request, typically in the Authorization: Bearer <token> header.
Unlike sessions, JWTs are stateless: the server does not need to store anything. All the information is encoded inside the token itself, and the server just verifies the signature.
The Three-Part Structure
A JWT is three Base64URL-encoded strings joined by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0IiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNzEwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Algorithm and token type. Always JSON: { "alg": "HS256", "typ": "JWT" }
Claims — the actual data. User ID, expiry, roles, any custom fields.
HMAC or RSA signature over header + payload. Proves the token has not been tampered with.
Standard Claims You Should Know
| Claim | Name | Purpose |
|---|---|---|
| iss | Issuer | Who issued the token (e.g. your auth server URL) |
| sub | Subject | Who the token is about — usually a user ID |
| aud | Audience | Who the token is intended for — validate this on the server |
| exp | Expiration | Unix timestamp after which the token is invalid |
| iat | Issued At | Unix timestamp when the token was created |
| nbf | Not Before | Token is invalid before this timestamp |
| jti | JWT ID | Unique identifier — used to prevent replay attacks |
You can add any custom claims you need (e.g. role, plan, org_id). Keep the payload small — it is not encrypted, just encoded.
Signing Algorithms: HS256 vs RS256 vs ES256
HS256 (HMAC-SHA256)
SymmetricUses a single shared secret to both sign and verify. Simple and fast. Use only when the signing and verifying parties are the same service.
Best for: Single-service apps, internal microservices that share a secret.
RS256 (RSA-SHA256)
AsymmetricUses a private key to sign and a public key to verify. Any service can verify without access to the private key.
Best for: Multi-service architectures, when you expose a JWKS endpoint for third-party verification.
ES256 (ECDSA-SHA256)
AsymmetricElliptic curve variant. Produces much shorter signatures than RS256 with equivalent security — better for bandwidth-constrained environments.
Best for: Mobile APIs, IoT, any scenario where token size matters.
JWT vs Session Cookies
| Property | JWT | Session Cookie |
|---|---|---|
| Storage | Client (localStorage / cookie) | Server (Redis / DB) |
| Stateless | ✅ Yes | ❌ No — server must store |
| Revocation | Hard — must use blocklist | Easy — delete session |
| Scalability | Excellent — no shared state | Requires sticky sessions or shared store |
| Payload visibility | Anyone can decode it | Opaque to the client |
| Best use case | Distributed systems, APIs | Traditional web apps, strict revocation needs |
6 Security Rules for JWT in Production
- Always validate the signature — never trust a JWT you have not verified.
- Check
expon every request — expired tokens must be rejected immediately. - Validate the
audclaim — a token issued for Service A must not be accepted by Service B. - Never store tokens in localStorage for sensitive apps — use
HttpOnlycookies to protect against XSS. - Keep access token lifetime short — 15 minutes is common. Use refresh tokens for longer sessions.
- Reject the
alg: noneattack — always specify the expected algorithm explicitly, never accept whatever the token claims.
Decode or generate JWTs instantly
Paste any JWT to inspect its header, payload, and verify its signature — or generate a signed token for testing.