Skip to main content

2026-03-03

9 min

By Formatho Editorial

Understanding JWT Tokens: A Complete Guide

JWTAuthenticationSecurity
Database dashboard representing time-sorted data and unique identifiers

Three parts, two dots

A JWT is header.payload.signature, each part Base64URL-encoded:

  • Header — {"alg":"HS256","typ":"JWT"}: which algorithm signed it.
  • Payload — claims: sub (subject), exp/iat/nbf (expiry/issued-at/not-before), iss/aud (issuer/audience), plus custom claims. Base64URL is encoding, not encryption — anyone can read the payload. Never put secrets in a JWT.
  • Signature — HS256: HMAC of the first two parts with a shared secret. RS256/ES256: signed with the issuer's private key; verifiable by anyone with the public key.

What the signature does and doesn't do

The signature guarantees integrity and authenticity — the claims are exactly what the issuer wrote. It does not guarantee confidentiality, revocation, or freshness beyond exp. A stolen but unexpired token works until it expires; keep lifetimes short (minutes) and use refresh tokens with rotation for sessions.

Verification checklist

  1. Split into three parts; decode header and payload.
  2. Pin the expected algorithm — verify alg is one you chose. The classic attack (alg=none / HS-vs-RS confusion) only works on verifiers that trust the header.
  3. Verify the signature with the right key (shared secret for HS*, issuer's public key for RS*/ES*).
  4. Check exp and nbf (in seconds), iss and aud match your expectations.
  5. Only then trust the claims.

Pitfalls seen in production

  • Leaking tokens in URLs — they land in logs, Referers, and history. Authorization headers only.
  • Storing long-lived JWTs in localStorage — any XSS reads them. Prefer httpOnly cookies with CSRF protection, or short in-memory tokens.
  • Ignoring exp on the client — "the API will 401 eventually" produces confusing failures; check expiry up front.
  • Confusing JWT and JWS/JWE — a signed JWT (JWS) is tamper-evident, not secret; an encrypted token (JWE) is a different object entirely.

Decode any token, inspect claims, and check expiry locally (nothing is transmitted) in the JWT Debugger.

Formatho Editorial — written and maintained by the team behind formatho.com, a library of free, privacy-first developer tools that run entirely in your browser. Every guide is tested against the tools it describes. Corrections and suggestions: github.com/formatho.