JWT Cheat Sheet
How JSON Web Tokens work, what every common claim and header means, which algorithm to choose, and the checks every server must make.
Cheat sheetPrintableFree, no login
Updated 28 October 2026
Decode a token, watch its expiry countdown and verify its signature — all in your browser.
Open the JWT decoderJWT structure
eyJhbGciOiJIUzI1NiJ9 . eyJzdWIiOiJ1MSIsImV4cCI6MTc5MzEzNjk0NH0 . 4QqPoCaM-dIEMoFGEy3...
└──── header ─────┘ └──────────────── payload ─────────────────┘ └── signature ──┘
{"alg":"HS256"} {"sub":"u1","exp":1793136944} HMAC or signature bytes- Three parts separated by dots, each Base64URL-encoded (no padding,
-and_instead of+and/). - The header and payload are encoded, not encrypted. Anyone with the token can read them. Never put passwords or secrets in a JWT.
- The signature covers
header.payload. Changing a single character of either breaks it. - Times (
exp,iat,nbf) are seconds since 1 January 1970 UTC, not milliseconds.
Registered claims
| Claim | Name | Type | Meaning |
|---|---|---|---|
iss | Issuer | String (URL) | Who created and signed the token |
sub | Subject | String | Who the token is about — usually the user ID |
aud | Audience | String or array | Who the token is meant for. The receiver must check it matches |
exp | Expiration time | Number (seconds) | Reject the token at or after this time |
nbf | Not before | Number (seconds) | Reject the token before this time |
iat | Issued at | Number (seconds) | When the token was created |
jti | JWT ID | String | Unique ID, used to block replays or revoke a token |
These seven are the registered claims from RFC 7519. All are optional, but most APIs require exp, iss and aud.
Common OpenID Connect and OAuth claims
| Claim | Meaning |
|---|---|
name given_name family_name | The user's names |
email email_verified | Email address and whether the provider checked it |
preferred_username | Username shown in apps |
picture | URL of the profile picture |
auth_time | When the user last signed in (seconds) |
nonce | Ties an ID token to one sign-in request, to stop replays |
azp | Authorized party — the client the token was issued to |
at_hash | Hash that binds an ID token to its access token |
amr acr | How the user signed in (e.g. pwd, mfa) and how strong that was |
scope / scp | Permissions granted to an access token (OAuth) |
roles groups | App or directory roles (provider-specific) |
Header fields
| Header field | Meaning | Note |
|---|---|---|
alg | Signing algorithm | Required. The receiver must check it against an allow-list |
typ | Token type, usually JWT | Optional; at+jwt marks OAuth access tokens |
kid | Key ID | Tells the receiver which key in its JWKS to use |
cty | Content type | Used for nested tokens |
jku x5u | URL of a key set or certificate | Only follow URLs you already trust |
jwk x5c | Key or certificate embedded in the header | Never verify a token with a key it carries itself |
Algorithms: HS256 vs RS256 vs ES256
| Algorithm | Type | Key | Use it when |
|---|---|---|---|
HS256 HS384 HS512 | HMAC (shared secret) | Random secret, at least 32 / 48 / 64 bytes | The same service creates and checks the token |
RS256 RS384 RS512 | RSA PKCS#1 v1.5 | RSA key pair, 2048 bits or more | Many services verify; most widely supported |
PS256 PS384 PS512 | RSA-PSS | RSA key pair, 2048 bits or more | Like RS256, with a more modern padding scheme |
ES256 ES384 ES512 | ECDSA (P-256 / P-384 / P-521) | EC key pair | Short signatures, fast — good for mobile and IoT |
EdDSA | Ed25519 | Ed25519 key pair | Modern and fast, where your libraries support it |
none | Unsigned | — | Never accept. Anyone can edit an unsigned token |
Security checklist
- Verify the signature on every request, with an allow-list of algorithms (e.g. only
RS256). Never let the token'salgchoose. - Reject
alg: noneand empty signatures. - Check
expandnbf, allowing at most a minute of clock skew. - Check
issandaud— a valid token from another app or issuer is not valid for yours. - Don't mix up key types: an RS256 public key must never be accepted as an HS256 secret (the "algorithm confusion" attack).
- Load keys only from a trusted JWKS URL, matched by
kid. Ignorejku,x5uandjwkin the token. - Keep access tokens short-lived (minutes) and use refresh tokens to renew them. A JWT can't be revoked before it expires unless you keep a deny-list of
jtivalues. - Use long random HMAC secrets — short ones can be brute-forced offline from a single token.
- Never put secrets in the payload. It's readable by anyone who sees the token.
Verify a JWT in code
Each example checks the signature with a fixed algorithm and validates the issuer, audience and expiry.
// Node.js — npm install jsonwebtoken
const jwt = require('jsonwebtoken');
const claims = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
issuer: 'https://auth.example.com',
audience: 'my-api',
});# Python — pip install pyjwt[crypto]
import jwt
claims = jwt.decode(
token, public_key,
algorithms=["RS256"],
issuer="https://auth.example.com",
audience="my-api",
)// Go — github.com/golang-jwt/jwt/v5
tok, err := jwt.Parse(tokenString,
func(t *jwt.Token) (any, error) { return publicKey, nil },
jwt.WithValidMethods([]string{"RS256"}),
jwt.WithIssuer("https://auth.example.com"),
jwt.WithAudience("my-api"),
)
Common JWT errors
| Error (Node.js jsonwebtoken) | Meaning | What to check |
|---|---|---|
jwt expired | The exp time has passed | Get a new token; check the server clock |
invalid signature | The signature doesn't match | Wrong secret or key, or the token was edited |
jwt malformed | Not three Base64URL parts | Missing Bearer handling, or a truncated token |
invalid algorithm | The token's alg isn't in your allow-list | Issuer and verifier must agree on the algorithm |
jwt audience invalid | aud doesn't match | The token was issued for another app |
jwt issuer invalid | iss doesn't match | The token comes from another issuer or environment |
jwt not active | Before the nbf time | Clock skew between servers |
Other libraries use similar wording, for example PyJWT raises ExpiredSignatureError and InvalidSignatureError.
Frequently asked questions
Is a JWT encrypted?
No — a normal JWT (a JWS) is only signed. The header and payload are Base64URL-encoded, so anyone with the token can read them. Encrypted JWTs (JWE) have five parts instead of three.
Can I decode a JWT without the secret?
Yes. Decoding only needs Base64URL. The secret or public key is needed to verify the signature, which proves the token wasn't changed.
Should I use HS256 or RS256?
Use HS256 when one service both creates and checks tokens and can keep a shared secret. Use RS256 (or ES256) when other services need to verify tokens: they get only the public key, so they can't create tokens.
How long should a JWT be valid?
Access tokens are usually valid for 5–60 minutes, paired with a longer-lived refresh token. Short lifetimes limit the damage if a token leaks, because JWTs can't easily be revoked.
What is the alg: none attack?
A token with
"alg": "none" has no signature, so anyone can change its claims. Some old libraries accepted these tokens. Always verify with a fixed list of allowed algorithms.