All posts

JSON Web Tokens (JWT) Explained: A Complete Guide for Developers

June 19, 2026 · DevTools

jwt
authentication
security
api

If you build APIs or web apps, you have met a JSON Web Token (JWT, pronounced "jot"). It is the string that gets handed around when a client proves who it is to a server. This guide explains what a JWT actually contains, how the signature works, and the security rules that catch people out.

You can follow along by pasting any token into the JWT Decoder — it runs entirely in your browser, so nothing is sent anywhere.

What is a JWT?

A JWT is a compact, URL-safe token defined in RFC 7519. It encodes a JSON "claim" payload and a cryptographic signature into a single string like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkRldkJlZSIsImlhdCI6MTcxODAwMDAwMCwiZXhwIjoxNzE4MDA4NDAwfQ
.s9Kq5x...signature...jQ

Three Base64url-encoded parts, separated by dots: header . payload . signature.

JWTs are popular for stateless authentication: the server issues a signed token, and every later request carries it. The server verifies the signature without looking up a session in a database.

The three parts

1. Header

A JSON object describing the token type and the signing algorithm:

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

alg is the important field. HS256 means HMAC with SHA-256 (symmetric — one shared secret). RS256 means RSA signature (asymmetric — a private key signs, a public key verifies). ES256 is the ECDSA equivalent.

2. Payload (claims)

A JSON object of claims — statements about the subject. Some are registered and have a standard meaning:

ClaimMeaning
issIssuer — who created the token
subSubject — who the token is about (often a user id)
audAudience — who the token is intended for
expExpiration time (must reject after this)
nbfNot before (must reject before this)
iatIssued at
jtiUnique token id (useful for revocation lists)

You can add any custom claims you like (name, role, scope).

Critical: the payload is Base64url-encoded, not encrypted. Anyone who can read the token can read the claims. A JWT guarantees integrity (it was not tampered with) and optionally authenticity — never confidentiality. Do not put passwords, secrets, or personal data you would not want exposed in the payload.

3. Signature

The signature proves the token has not been modified. For HS256:

HMAC-SHA256(
  secret,
  base64url(header) + "." + base64url(payload)
)

The result is appended as the third part. To verify, the receiver recomputes the HMAC with the same secret and compares. If even one byte of the header or payload changed, the signature will not match. Try creating and signing one yourself with the JWT Signer.

Base64url, not Base64

JWTs use Base64url encoding, which differs from standard Base64 in two ways:

  • + becomes - and / becomes _ (so the token is safe in a URL).
  • Padding = characters are stripped.

This is why pasting a JWT into a normal Base64 decoder sometimes fails — the decoder must restore the padding and swap the URL-safe characters first. (The JWT Decoder handles this for you.)

Signing algorithms: HS256 vs RS256

HS256 (HMAC + SHA-256) is symmetric. Both the issuer and the verifier share the same secret. Simple, but the secret must be distributed to every service that verifies tokens.

RS256 (RSA) is asymmetric. The issuer signs with a private key; verifiers only need the public key. This is the standard choice when you have many services or a third party (like an OAuth/OIDC provider) issuing tokens that you only need to verify.

You can explore HMAC signing outside of JWTs with the HMAC Generator.

Decoding vs verifying — they are not the same

  • Decoding means Base64url-decoding the header and payload so you can read them. Anyone can do this; it requires no secret.
  • Verifying means recomputing the signature and checking the claims (exp, aud, iss…) so you can trust the token. This requires the secret or public key.

Reading a token is useful for debugging. Trusting a token is what your server must do before acting on it.

Security checklist

  1. Never store secrets in the payload. It is readable by anyone.
  2. Always set a short exp. An hour is typical; refresh tokens last longer.
  3. Verify the signature and the alg. Reject alg: none outright — a well-known attack relies on libraries that skip verification when the algorithm is "none".
  4. Validate aud and iss. A token minted for service A must not be accepted by service B.
  5. Keep the signing secret private. If it leaks, every token it signed is forgeable.
  6. Use HTTPS. Tokens in transit must be encrypted by the transport.

When to use a JWT (and when not to)

JWTs shine for stateless, short-lived API authentication and for federated identity (OAuth 2.0 / OpenID Connect), where one authority signs tokens that many services verify.

They are a poor fit when you need immediate revocation — a signed token is valid until it expires unless you maintain a blocklist of jtis, which gives up the main benefit of being stateless. For sessions you must kill instantly, a server-side session store is often simpler.

Try it

Paste a token into the JWT Decoder to read its header and claims, or build and sign your own with the JWT Signer. Both run entirely in your browser.

Tools mentioned in this post