Home · Blog · JWT Tokens Explained
Auth · Security

JWT Tokens Explained Simply

A JWT is three Base64URL chunks separated by dots. That's it. Here's what each chunk means, how signing keeps them honest, and the mistakes that keep landing in security audits.

10 min read·Updated June 2026

The three parts

A JSON Web Token looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjMiLCJuYW1lIjoiQWRhIiwiZXhwIjoxNzM1Njg5NjAwfQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Three Base64URL-encoded strings separated by dots: header, payload, signature.

Header

Tells the verifier which algorithm to use.

{ "alg": "HS256", "typ": "JWT" }

Payload (claims)

JSON object of claims. Some are standardized:

Custom claims live alongside these. Keep the payload small — every request carries it.

Signature

The signature is computed over base64url(header) + "." + base64url(payload) using the algorithm declared in the header. With HS256, that's an HMAC-SHA256 with a shared secret. With RS256, it's RSA-SHA256 with a private key.

Read, don't trustYou can decode any JWT in your browser without the secret — the payload is just Base64URL. Try it in the JWT Decoder. Decoding ≠ verifying.

How verification actually works

  1. Split the token on . into three parts.
  2. Base64URL-decode the header and read alg.
  3. Recompute the signature over header.payload using your key.
  4. Compare against the provided signature in constant time.
  5. If it matches, validate the claims: exp in the future, nbf in the past, iss/aud match what you expect.

Expiration: exp, nbf, iat

All three are Unix timestamps in seconds, not milliseconds. A 10-minute token issued now has exp = Math.floor(Date.now()/1000) + 600. Clock skew is the most common source of "token not yet valid" errors — allow a few seconds of leeway on both ends.

Security mistakes that keep happening

1. Accepting alg: none

Some early libraries honored a header of {"alg":"none"} and skipped signature verification entirely. An attacker could forge any payload. Hardcode the expected algorithm on the server — never derive it from the incoming header.

2. HS256 / RS256 confusion

If your server accepts both and uses the RSA public key as the HMAC secret, an attacker can sign tokens with HS256 using that public key. Pin one algorithm per endpoint.

3. Storing tokens in localStorage

Any XSS on your origin reads localStorage instantly. Prefer an httpOnly, Secure, SameSite=Lax cookie. If you must use localStorage (e.g. for a single-page app calling a different origin), keep token lifetimes short.

4. Putting secrets in the payload

The payload is readable by anyone. Don't include PII you wouldn't expose in an API response. Don't put database connection strings or feature flags an attacker shouldn't see.

5. No revocation strategy

JWTs are stateless. Once issued, they're valid until exp. Plan for the day you need to revoke one: short-lived access tokens (5–15 min) plus a refresh token with a server-side allowlist is the common pattern.

When JWTs are the wrong choice

JWTs shine for service-to-service auth, OAuth/OIDC flows, and stateless APIs where the issuer and verifier are different parties. For a classic single-server web app with a session, an opaque session cookie is simpler, smaller, and trivially revocable.

Debugging tipWhen a token mysteriously fails, decode it and check three things first: exp vs current time, aud against your service ID, and alg against your expected algorithm.

FAQ

Is a JWT encrypted?
By default no. A standard JWT (JWS) is signed but not encrypted — anyone holding the token can read the payload. Use JWE if you need encryption.
Where should I store a JWT in the browser?
Prefer an httpOnly, Secure, SameSite cookie. localStorage exposes the token to any XSS on your origin.
What does exp mean in a JWT?
exp is the expiration time as a Unix timestamp in seconds. Servers reject tokens whose exp is in the past (allowing for a few seconds of clock skew).
Can I shorten a JWT?
Only by trimming the payload. The structure is fixed. Avoid bloating claims; if a token is over 1–2 KB, reconsider what you're including.