Guide

JWTs explained: structure, claims, decoding vs verifying, and common mistakes

How JSON Web Tokens work, what each part and claim means, why decoding isn't verifying, and the mistakes that cause real security bugs.

How we made this: Technical explainer based on the IETF specifications (RFC 7519 JWT, RFC 7515 JWS, RFC 7518 JWA, RFC 8725 JWT Best Current Practices). Code-level advice is general; follow your framework's and identity provider's documentation. Editorial policy.

A JSON Web Token (JWT) is a compact, URL-safe way to pass a set of claims, such as “this is user 42 and they’re an editor”, between systems. The token is signed, so the receiver can check that it hasn’t been changed. Most APIs and identity providers (OAuth 2.0, OpenID Connect) use them.

Inspect a token now: the JWT decoder shows the header and claims, converts times to dates, flags common problems and can verify the signature. It runs entirely in your browser.

The three parts

A signed JWT is three Base64URL strings separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 . eyJzdWIiOiI0MiIsInJvbGUiOiJlZGl0b3IifQ . 3q2-7w…
          header                              payload                         signature
  1. Header: which algorithm signed the token, e.g. {"alg":"HS256","typ":"JWT"}, and sometimes a key ID (kid).
  2. Payload: the claims, e.g. {"sub":"42","role":"editor","exp":1767225600}.
  3. Signature: computed over header.payload with a secret or private key.

Base64URL is ordinary Base64 with - and _ instead of + and /, and no = padding. You can decode any part with the Base64 decoder. That’s the point to remember: the payload is readable by anyone who has the token.

Registered claims

These have defined meanings (RFC 7519 §4.1):

ClaimMeaningCheck on the server
issIssuer: who created the tokenMatches the issuer you trust
subSubject: who it’s about (often a user ID)Exists in your system
audAudience: who it’s forIncludes your API
expExpiry timeNow is before exp
nbfNot valid beforeNow is after nbf
iatIssued atPlausible, not in the future
jtiUnique token IDNot reused, if you track IDs

Times are NumericDates: seconds since 1970-01-01 UTC, not milliseconds. Writing exp in milliseconds is a classic bug: the token then appears valid for thousands of years. The Unix timestamp converter and the JWT decoder both show these as readable dates.

Decoding is not verifying

Decoding shows what a token claims. Anyone can write a header and payload, encode them and stick them together. Only the signature proves who issued the token:

  • HS256/384/512 (HMAC): the issuer and verifier share one secret. Anyone who can verify can also sign, so keep the secret on servers only. Use a random secret at least as long as the hash: 32 bytes for HS256.
  • RS256, PS256 (RSA), ES256 (ECDSA), EdDSA: the issuer signs with a private key, and anyone can verify with the public key, often published as a JWKS at a well-known URL.

The JWT decoder can verify all of these with your browser’s Web Crypto API: paste the secret, or the public key as PEM or JWK. A verified signature tells you the token is authentic. It doesn’t tell you whether your application should accept it. That’s the server’s job.

How servers should validate a token

Use a maintained library, and make sure it does all of this (see RFC 8725, JWT Best Current Practices):

  1. Pin the algorithm. Accept only the algorithm you expect for that key. Never let the token’s header choose. This blocks alg: none tokens, and “algorithm confusion”, where an RS256 public key is misused as an HS256 secret.
  2. Verify the signature with the right key, choosing by kid only from keys you already trust.
  3. Check exp and nbf, allowing a small clock skew (a minute or so).
  4. Check iss and aud, so a token issued for another service isn’t accepted by yours.
  5. Then apply your own rules, such as roles, scopes and whether the user still exists.

Common mistakes

  • Putting sensitive data in the payload. It’s only encoded. Use opaque IDs, and look the details up on the server.
  • Long-lived tokens. A stolen token works until it expires. Keep access tokens short-lived and use revocable refresh tokens.
  • Treating “decoded fine” as “valid”. Client-side code can read claims for display, but authorisation decisions belong on the server, after verification.
  • Logging tokens. Access logs, error trackers and support tickets are a common source of leaks. Redact the Authorization header.
  • Weak HMAC secrets. Short or guessable secrets can be brute-forced offline from a single token.

Where to store tokens in the browser

There’s no perfect answer. HttpOnly, Secure, SameSite cookies can’t be read by JavaScript, which limits the damage from XSS, but you need CSRF protection. localStorage is simple, but any script on the page can read it. Many teams use cookies for refresh tokens and keep short-lived access tokens in memory. Follow your framework’s guidance, and fix XSS first: whichever storage you pick, injected scripts can act as the user.

This guide is general technical information. Security requirements depend on your system, so review them with your team or a security professional.

Frequently asked questions

Is the data in a JWT encrypted?

Not in an ordinary signed JWT (JWS). The header and payload are only Base64URL-encoded, so anyone with the token can read them. Don’t put secrets or sensitive personal data in the payload. Encrypted tokens (JWE) exist but are less common.

Can I trust the alg in the header?

No. The header is attacker-controlled. Your server should accept only the algorithm(s) it expects for that issuer and key, and reject everything else — especially alg: none.

How do I log someone out if JWTs can’t be revoked?

Use short-lived access tokens (minutes, not days), refresh tokens that you can revoke on the server, and — where you need instant revocation — a deny-list checked on each request.

Tools mentioned

GitHub Copilot

AI Coding

GitHub’s AI pair programmer. It suggests code as you type and offers a chat assistant inside popular code editors and on GitHub itself.

Main use
Writing boilerplate faster
Free plan
Not yet verified
Pricing
Not yet verified
Last reviewed
Not yet reviewed

Cursor

AI Coding

An AI-first code editor built on the same foundations as Visual Studio Code. It lets you chat with your codebase and ask the AI to make…

Main use
Refactoring
Free plan
Not yet verified
Pricing
Not yet verified
Last reviewed
Not yet reviewed

You may also need

Free tools and pages that help with the same job.

Explore categories