A JSON Web Token (JWT, pronounced “jot”) is a compact, signed piece of JSON that proves who a user is or what they are allowed to do. After you sign in, many apps and APIs give your browser or phone a JWT and expect it back with every request, usually in an Authorization: Bearer … header. Here is how they work, how to read one and how to use them safely.
The three parts
A JWT is three Base64URL-encoded pieces joined by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- Header: the token type and signing algorithm, for example
{"alg": "HS256", "typ": "JWT"}. - Payload: the claims, such as the user ID (
sub), when the token was issued (iat) and when it expires (exp). - Signature: a cryptographic signature over the header and payload, made with a secret or a private key.
Encoded is not encrypted
Base64URL is just an encoding: anyone who has a JWT can read its header and payload, without any key. The signature only proves the token has not been changed and was issued by someone holding the key. So:
- Never put secrets such as passwords, card numbers or private data in a JWT payload.
- If the contents must be hidden, use an encrypted token (JWE, which has five parts) or keep the data on the server.
Common claims
| Claim | Meaning |
|---|---|
iss | Issuer: who created the token |
sub | Subject: usually the user ID |
aud | Audience: which API or app the token is for |
exp | Expiry time, in seconds since 1 January 1970 (Unix time) |
nbf | Not valid before this time |
iat | Issued at |
jti | A unique token ID, useful for revoking tokens |
The JWT Decoder shows these times as real dates, with “expires in 2 hours” or “expired 3 days ago”.
Decoding versus verifying
Decoding just reads the parts. Verifying recalculates the signature with the right key and checks it matches. A server must always verify, and must also check that the token has not expired and that iss and aud are what it expects. Reading a token in your app without verifying it is fine for display, but never for making security decisions.
HS256 and RS256
- HS256 (HMAC) uses one shared secret to sign and verify. Simple, but every service that verifies tokens also holds the key that can create them.
- RS256, PS256 and ES256 sign with a private key and verify with a public key. Services can verify tokens without being able to forge them, which is why identity providers publish their public keys as a JWKS.
Security mistakes to avoid
- Accepting
alg: none: an unsigned token must always be rejected. Fix the expected algorithm on the server instead of trusting the header. - Weak HMAC secrets: use at least 32 random bytes; short secrets can be guessed offline.
- Long-lived tokens: keep access tokens short (minutes to an hour) and use refresh tokens to get new ones.
- Storing tokens where scripts can read them: a token in
localStoragecan be stolen by any cross-site scripting bug. Many apps keep tokens in secure, HttpOnly cookies instead. - Pasting live tokens into online tools: a valid token is as good as a password until it expires. Use test tokens, or tools that run entirely in your browser like this site’s decoder.
Frequently asked questions
Can a JWT be cancelled before it expires?
Not by itself; it stays valid until exp. To revoke tokens early, keep a deny-list of token IDs (jti) on the server, or keep access tokens short-lived.
Is a JWT the same as OAuth?
No. OAuth 2.0 is a way to grant access; JWT is a token format. Many OAuth and OpenID Connect providers issue JWTs as access or ID tokens, but OAuth tokens can also be random strings.