JSON Web Tokens (JWT)
A JSON Web Token (JWT) is a compact, URL-safe way to transmit signed claims between two parties. In web and mobile apps, JWTs are most often used as bearer access tokens for stateless authentication — the server can verify them without a database lookup.
That convenience comes with sharp edges: a JWT is signed, not encrypted, and it stays valid until it expires whether or not the user "logged out." Using JWTs safely is mostly about strict validation and short lifetimes.
TL;DR
- A JWT is three base64url segments:
header.payload.signature. - Signed (JWS) means tamper-evident, not secret — anyone can read the payload.
- Validate strictly: signature,
exp,iss,aud, and a pinned algorithm. - Keep access tokens short-lived (5–15 min); use refresh tokens or server sessions for long-lived login.
- Never accept
alg: none, and never put secrets in the payload.
Quick Example
Signing and verifying a token in Node.js, with the algorithm pinned and claims enforced:
Core Concepts
Anatomy of a token
A JWT has three parts, separated by dots:
- Header — metadata, e.g. the signing algorithm (
alg) and type (typ). - Payload — the claims (user id, scopes, expiry…).
- Signature — proves the header and payload weren't altered.
⚠️ base64url is not encryption. Anyone holding the token can decode and read the payload. Never put passwords, keys, or PII in it.
Common claims
Registered claims you'll see often:
sub— subject (usually the user id)iss— issuer (who minted the token)aud— audience (who it's for)exp— expiry timestampiat/nbf— issued-at / not-before
App-specific claims often add scope/scopes, role/roles, or org_id/tenant_id.
Algorithms: HS256 vs RS256
Rule of thumb: reach for RS256/ES256 as soon as more than one service (or an external party) needs to verify tokens.
Validation Checklist
When your API receives a token, do all of this — skipping any step is a common vulnerability:
- Extract it from
Authorization: Bearer <token>. - Verify the signature with the correct key.
- Pin the algorithm — never accept
none, never trust the token's ownalg. - Check
exp(andnbfif present). - Check
issmatches your issuer andaudmatches your API. - Apply authorization (roles/scopes) — see API Security.
JWT vs Sessions
JWTs aren't "better sessions" — they're a different trade-off.
Many production apps do both: cookie-backed sessions for the browser, JWT access tokens for service-to-service calls.
Refresh Tokens
Access tokens should be short-lived. For persistent login, pair them with a refresh token:
- Issue a longer-lived refresh token, stored in an
HttpOnlycookie. - Rotate it on every use and support revocation.
Storage Guidance
- Browser: prefer
HttpOnly,Securecookies for refresh tokens (reduces theft via XSS). Keep access tokens in memory and short-lived. AvoidlocalStorageunless you fully accept the XSS trade-off. - Mobile: store tokens in platform secure storage (Keychain / Keystore); use PKCE with the system browser for login.
Best Practices
Pin the algorithm
Always pass an explicit algorithms allowlist to your verifier so an attacker can't downgrade to none or swap RS256 for HS256.
Keep tokens short-lived
Short exp windows limit the blast radius of a stolen token, since you can't easily revoke a JWT.
Verify iss and aud
A token minted for another service or audience must be rejected, even if the signature is valid.
Common Mistakes
Accepting any algorithm
Skipping audience/issuer checks
Treating "logout" as revocation
Deleting a token client-side doesn't invalidate it. If you need real revocation, use short lifetimes plus a deny-list or server-side sessions.
FAQ
Are JWTs encrypted?
No. A standard signed JWT (JWS) is only tamper-evident — the payload is base64url and readable by anyone. If you need confidentiality, use JWE, or simply don't put sensitive data in the token.
Can you revoke a JWT?
Not directly — it's valid until exp. Practical options are short lifetimes, a server-side deny-list of token IDs (jti), or rotating the signing key to invalidate everything at once.
Should I use HS256 or RS256?
Use HS256 only when one trusted party both signs and verifies. Use RS256/ES256 when multiple services or external parties verify tokens, so you only distribute the public key.
Where should I store a JWT in a browser?
Prefer an HttpOnly cookie for the refresh token and keep a short-lived access token in memory. localStorage is readable by any XSS, so avoid it for sensitive tokens.
How long should a JWT last?
Access tokens: minutes (5–15). Refresh tokens: days to weeks, rotated on use. Shorter access tokens reduce the damage from theft.
Related Topics
- API Security — Where JWTs fit in endpoint protection
- OAuth 2.0 — Flows that issue JWT access/ID tokens
- Authentication — Sessions vs tokens vs passwordless
- Password Security — Protecting the login that mints tokens
- HTTPS & TLS — Keeping bearer tokens off the wire in cleartext