A JSON Web Token (JWT, often pronounced "jot") is a compact, signed way to carry claims — like "who this user is" — between two parties. It's the format behind most modern API authentication. This guide explains exactly how it works, what's safe to put in one, and the mistakes to avoid.
Decode a JWT now (in your browser) →A JWT is three Base64URL-encoded sections joined by dots: header.payload.signature.
eyJhbGciOiJIUzI1NiJ9 ← header .eyJzdWIiOiIxMjMiLCJleHAiOjE3MDAwMDAwMDB9 ← payload .dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk ← signature
{"alg":"HS256","typ":"JWT"}.| Claim | Meaning |
|---|---|
iss | Issuer — who created the token |
sub | Subject — usually the user ID |
aud | Audience — who the token is for |
exp | Expiration time (Unix seconds) — reject after this |
nbf | Not before — reject earlier than this |
iat | Issued at (Unix seconds) |
Times are Unix timestamps in seconds — convert them with the timestamp converter.
The signature is what makes a JWT trustworthy. The issuer signs header.payload with a key; the receiver re-computes the signature and checks it matches.
Signs and verifies with the same secret (HMAC-SHA256). Simple, but every party that verifies also holds the signing secret. Use a long, random secret.
Signs with a private key and verifies with a public key. Better when many services need to verify but only one should issue — they only get the public key. Standard for OIDC / "sign in with…" flows.
Decoding just Base64URL-decodes the header and payload so you can read them. Verifying checks the signature against the key and confirms the token isn't expired or tampered with. Reading a token tells you what it claims; only verification tells you whether to trust it. A server must always verify; a developer inspecting a token just decodes it.
alg: none. Some libraries once accepted unsigned tokens. Always pin the expected algorithm.exp. Decoding without verifying expiry lets stale tokens through.exp short and use refresh tokens.