How to Decode a JWT: Read the Header, Payload, and Signature Yourself
Learn how to decode a JWT by hand, what each of the three segments holds, and why decoding is not the same as verifying. Includes a worked example and the exp/iat claims that trip up most debugging.
How to Decode a JWT: Read the Header, Payload, and Signature Yourself
A JSON Web Token looks like one long unreadable string, but it is not encrypted — it is just three Base64URL chunks glued together with dots. Once you know how to read those chunks, a JWT stops being a mystery box and becomes a debugging tool you can inspect in seconds. This guide walks through the three-part structure, the claims that matter most, the security line between decoding and verifying, and why doing the decode locally is the safer habit.
The three segments: header.payload.signature
Every standard signed JWT (technically a JWS) has exactly three parts separated by periods:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Split it on the dots and Base64URL-decode the first two parts and you get plain JSON. The first segment is the header:
{ "alg": "HS256", "typ": "JWT" }
The second is the payload — the claims:
{
"sub": "1234567890",
"name": "Jane Doe",
"iat": 1516239022,
"exp": 1516242622
}
The third segment, SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c, is the signature. It is a cryptographic hash of the first two segments computed with a secret or private key, and it is the only part you cannot read as JSON. That signature is what a server checks to confirm the token has not been altered. Paste a token into the JWT Decoder and you see those three sections laid out instantly, with the timestamps already converted to human dates.
Decoding is not verifying — and that distinction matters
This is the single most important thing to understand. Decoding answers the question "what does this token claim?" Verifying answers "is this token genuine and untampered?" They are completely different operations.
Anyone can take the worked example above, flip "name": "Jane Doe" to "name": "Admin", re-Base64-encode it, and the result still decodes perfectly cleanly. What it will not do is pass signature verification, because the signature no longer matches the modified payload. The structure for these tokens is defined in RFC 7519, and the signing/verification rules live in the companion JWS spec, RFC 7515. The takeaway from those specs is blunt: a successful decode tells you nothing about authenticity.
That is why a decoder should never ask for your signing secret. Verification belongs on the server, using a library like jose (Node) or pyjwt (Python) that holds the issuer's key. A browser decoder is a read-only lens — useful for inspection, useless and dangerous as a trust check. If you treat "it decoded" as "it's valid," you have a security hole, not a debugging win.
The claims that actually matter when something breaks
Most JWT debugging comes down to three timestamp claims, all of them Unix seconds (not milliseconds):
iat— issued at. When the token was minted.exp— expires at. After this moment the token is dead.nbf— not before. The token is invalid until this time arrives.
When an API throws a 401, the first move is to read exp and compare it to right now. If exp is 1716200000 and that timestamp is three minutes in the past, the token simply expired and the client needs to refresh — that is not a permissions bug, and chasing it as one wastes half an hour. A second common failure is clock skew: if iat reads as a time in the future from the receiving server's point of view, the two hosts disagree on the wall clock and nbf validation trips. The fix there is NTP on the machines, not your code, and the decoded timestamps are the proof.
Beyond timestamps, sub (the subject, usually a user ID), iss (the issuer), and custom scope/roles claims are what you read when a login works but a permission check fails. And in the header, kid (key ID) tells you which signing key an SSO provider used — invaluable during an Okta or Auth0 key rotation when verification suddenly starts failing.
A debugging story from my own week
I once spent the better part of a morning convinced our gateway had a broken role-mapping bug. Requests to an admin route kept bouncing with 403, the user swore they were an admin, and the code looked correct. When I finally stopped reading source and pasted the actual token into a decoder, the payload showed scope: "read:orders" — the auth server had issued the token with the wrong scope entirely. The route guard was fine; the token was wrong at the source. A ten-second decode would have saved me three hours of reading the wrong file. Since then, "decode the token first" is the first step in every auth bug I touch.
Why decoding locally is the safer habit
A JWT is a credential. Even though decoding is mathematically just a Base64URL decode plus a JSON.parse — operations that can run entirely in your browser with no network call — where you paste the token still matters. Clipboard history, browser extensions, and sketchy online decoders that POST your input to a server are all real leak vectors. A token in someone else's logs is a token someone else can replay until it expires.
So two rules. First, prefer a decoder that does everything client-side and deliberately does not sync the token into the URL, so you never leak it by copying or bookmarking the page. Second, for genuine production tokens, decode on a trusted local tool and rotate the secret if a token was ever exposed. If you also need to build test tokens to reproduce a bug, the JWT Encoder lets you assemble a header and payload locally, and when you just want to eyeball the raw Base64 segments themselves, the Base64 Encoder decodes any single chunk on its own.
Wrapping up
A JWT is readable by design — three Base64URL segments, two of them plain JSON, one of them a signature you check but don't read. Decode it to understand what it claims (exp, iat, sub, scope, kid), verify it on the server to trust it, and keep the whole process on a tool that never ships your credential off your machine. Do that and most auth bugs collapse from a multi-hour hunt into a ten-second glance.
Made by Toolora · Updated 2026-06-13