How to Decode a JWT and Read Its Claims
Learn how to split and Base64URL-decode a JWT, interpret standard claims like exp and aud, and verify the signature before trusting a token.
To decode a JWT, split the token at its two dots and Base64URL-decode the first two segments: the header and the payload. The result is readable JSON; the third segment is the signature, which decoding shows but does not verify.
What a JWT contains
Most tokens people call JWTs are signed JWTs, or JWS compact serialization. They contain three Base64URL segments separated by dots:
header.payload.signature
Here is a small example. The last segment is a placeholder, so this token is only for reading; a real signature can only be produced by the holder of the signing key.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEwNDIiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3OTI3MTM2MDAsImV4cCI6MTc5MjcxNzIwMH0.ZGVtby1zaWduYXR1cmUtcGxhY2Vob2xkZXI
| Segment | Typical content | What decoding reveals |
|---|---|---|
| header | Algorithm, token type, and optional key ID | How the token says it is signed |
| payload | Registered and app-specific claims | Identity, times, audience, and permissions |
| signature | Raw signature bytes, encoded as Base64URL | Nothing useful without the issuer's key |
Encrypted JWTs (JWE) are a different format with five segments. This guide covers the three-part signed tokens used by most auth providers.
How to decode a JWT step by step
Copy the compact token
Take the token from the Authorization: Bearer header, an HttpOnly cookie, or your auth library. A signed JWT has three segments separated by two dots.
Split it into three segments
Split on "." to get the header, payload, and signature. If you do not get exactly three non-empty parts, the value is not a signed JWT.
Base64URL-decode the header and payload
Decode the first two segments with Base64URL, then parse the resulting UTF-8 text as JSON. The signature is binary data encoded for transport, not a JSON object.
Read the claims and timestamps
Inspect iss, sub, aud, exp, nbf, iat, and jti, plus any app-specific claims. Timestamps are seconds since the Unix epoch, not milliseconds.
Verify the signature before trusting the token
Use the issuer's key and a maintained JWT library to verify the signature, algorithm, audience, issuer, and time claims. Decoding alone proves nothing about authenticity.
Decoding the segments in JavaScript
In Node.js, the base64url encoding handles the URL-safe alphabet and missing padding for you:
const [headerPart, payloadPart] = token.split(".");
const decode = (part) =>
JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
console.log(decode(headerPart));
console.log(decode(payloadPart));Browsers do not have Buffer, so use atob after replacing - with +, _ with /, and restoring the = padding. Then convert the binary string returned by atob to bytes and decode them with TextDecoder, because atob alone does not correctly decode non-ASCII UTF-8 claims:
const decodePart = (part) => {
const pad = part.length % 4 === 2 ? "==" : part.length % 4 === 3 ? "=" : "";
const base64 = part.replace(/-/g, "+").replace(/_/g, "/") + pad;
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
return JSON.parse(new TextDecoder("utf-8").decode(bytes));
};The JWT Decoder below does that for you and displays the claims in a readable form.
For the example above, the decoded header and payload are:
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "user_1042",
"role": "admin",
"iat": 1792713600,
"exp": 1792717200
}The timestamps decode to 2026-10-23 00:00:00 and 01:00:00 UTC. The token is designed to expire one hour after it was issued.
What the JWT claims mean
The payload is a JSON object called the claims set. Some claim names are registered by the JWT specification and have defined meanings:
| Claim | Meaning | Example |
|---|---|---|
| iss | Issuer that created and signed the token | https://auth.example.com |
| sub | Subject the token is about, usually a user ID | user_1042 |
| aud | Audience the token is intended for | api://orders |
| exp | Expiration time; the token must not be accepted at or after it | 1792717200 |
| nbf | Not before; the token must not be accepted before it | 1792713600 |
| iat | Time the token was issued | 1792713600 |
| jti | Unique token ID, useful for replay detection and revocation | 9f1c2a7e |
Custom claims and authorization data
Claims such as role, plan, or tenant_id are app-specific, not part of the JWT standard. They are still readable by anyone holding the token, so they must never contain passwords, API keys, or sensitive personal data. Treat them as hints until the signature and claim checks pass.
What a decoded JWT does and does not prove
Base64URL is an encoding, not encryption. Anyone with the token can read every claim. Decoding tells you what a token claims; verification tells you whether those claims were signed by a trusted issuer and have not been altered.
| Question | Decoding | Verifying |
|---|---|---|
| Needs a secret or public key? | No | Yes |
| Proves who issued the token? | No | Yes, if the key is trusted |
| Detects a modified payload? | No | Yes |
| Safe for authorization decisions? | No | Only after claim checks |
| Typical implementation | Base64URL decode plus JSON parse | JWT library and trusted key |
JWT security checklist
- Verify the signature with a trusted key before accepting a token.
- Pin the expected algorithms and reject
alg: none. - Check
exp,nbf,aud, andiss. - Use a maintained JWT library instead of hand-rolled crypto.
- Do not treat a decoded payload as proof of identity or permission.
- Do not put secrets or unnecessary personal data in claims.
- Do not trust a token just because its expiry is in the future.
- Do not use a third-party decoder that uploads tokens to a server.
A decoded token can also be expired, issued for another audience, or signed with an algorithm you did not expect. Those are all reasons to verify rather than just decode.
Decode a token in your browser
The JWT Decoder & Inspector splits and decodes the header and payload locally, shows human-readable claims and expiry status, and lets you verify supported signatures. Nothing is uploaded, which makes it a safer place to inspect a token than a service that posts it to a backend.
// Frequently Asked Questions
Can I decode a JWT without the secret key?
Yes. The header and payload are Base64URL-encoded, not encrypted, so anyone with the token can decode and read them. A key is only needed to create or verify the signature: the shared secret for HMAC, or the private and public halves of an RSA or ECDSA key pair.
Is it safe to paste a JWT into an online decoder?
Only if the tool processes the token locally in your browser. A JWT is a bearer credential, so a tool that uploads it to a server exposes it to that server and its logs. The CODERCOPS JWT Decoder runs entirely client-side.
Does decoding a JWT verify that it is valid?
No. Decoding only reveals the contents. Verification checks the signature with a trusted key and checks claims such as exp, nbf, aud, and iss. A token can decode perfectly and still be forged, expired, or issued for another audience.
Why do JWT timestamps look like 1792713600?
JWT NumericDate values count seconds since 1970-01-01 UTC. Multiply by 1000 to get JavaScript milliseconds, or use a decoder that displays the human-readable date for exp, nbf, and iat.