JSON Web Tokens (JWTs) are everywhere in modern web auth. If you’ve ever worked with authentication, you’ve probably encountered one. Here’s how to decode a JWT and read its claims — and why verification matters.
What Is a JWT?
A JWT is a compact, URL-safe way to represent claims between two parties. It’s commonly used for stateless authentication in SPAs and APIs.
A JWT looks like this:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjgzOTAyMiwiZXhwIjoxNzM4NDE1MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
It has three parts separated by dots: Header, Payload, Signature.
The Three Parts of a JWT
1. Header
Base64URL-encoded JSON containing metadata:
{
"alg": "HS256",
"typ": "JWT"
}
HS256 means the signature was created using HMAC-SHA256.
2. Payload
Base64URL-encoded JSON containing the claims — statements about the user:
{
"sub": "1234567890",
"name": "Jane Doe",
"admin": true,
"iat": 1516839022,
"exp": 1734415022
}
Key claims:
sub— subject (usually the user ID)iat— issued at (Unix timestamp)exp— expiration time (Unix timestamp)admin— custom claim example
3. Signature
The header and payload are signed with a secret key. This proves the token wasn’t tampered with. Without verification, anyone can modify the payload and re-encode it.
How to Decode a JWT
You can decode the header and payload (not the signature) without a key:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
↓ Base64URL decode
{"alg":"HS256","typ":"JWT"}
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjgzOTAyMiwiZXhwIjoxNzM4NDE1MDIyfQ
↓ Base64URL decode
{"sub":"1234567890","name":"Jane Doe","admin":true,"iat":1516839022,"exp":1734415022}
Important: Decoding only reads the claims. It does NOT verify the signature. Only the signature step confirms the token hasn’t been tampered with.
How to Check If a JWT Is Expired
The exp claim contains a Unix timestamp of when the token expires. Compare it to the current time:
const exp = 1734415022; // from token payload
const now = Math.floor(Date.now() / 1000);
if (exp < now) {
console.log("Token is expired");
} else {
console.log("Token is still valid");
}
Unix timestamps are seconds since January 1, 1970. The above example token expires on December 17, 2024.
Why Signature Verification Matters
You should never trust a JWT based solely on decoded claims. Without verifying the signature:
- An attacker can modify the payload to set
admin: true - They can change
subto any user ID - They can extend or remove the
expclaim - They re-encode header + payload and forge a token
A server must verify the signature using the secret key (or public key for asymmetric algorithms) before trusting any claim.
Common JWT Algorithms
| Algorithm | Type | Use | |-----------|------|-----| | HS256 | Symmetric | Shared secret key | | HS384 | Symmetric | Shared secret key | | HS512 | Symmetric | Shared secret key | | RS256 | Asymmetric | Public/private key pair | | RS384 | Asymmetric | Public/private key pair | | RS512 | Asymmetric | Public/private key pair | | ES256 | Asymmetric | ECDSA with P-256 curve |
Summary
A JWT has three parts: header, payload, and signature. The header and payload are Base64URL-encoded JSON anyone can decode. The signature must be verified with a key to prove authenticity. Always check exp to see if a token has expired.
Decode any JWT instantly with the JWT Decoder — paste your token and read all claims right in the browser.