JWT Decoder
Decode a JWT header and payload from base64url, with alg plus epoch, UTC and relative times for iat, nbf and exp claims.
JWT Decoder workspace
Source Editor
Press Ctrl/Cmd + Enter to run.
Your draft is kept in this tab only (sessionStorage) and disappears when the tab closes. .
Result Console
Using JWT Decoder
Paste the token into the editor, or press Load example to see the layout on a sample token.
Press Decode Token to split it on the dots and decode the first two segments.
Read the header for alg and kid, and the payload for the claims your application relies on.
Check the iat, nbf and exp rows, shown as raw epoch seconds, UTC and relative local time.
The three dot-separated segments are decoded from base64url, so the hyphens and underscores that appear in most real tokens are handled correctly and multibyte claim values come back intact. Signatures are never checked, and the interface and the copied output both say so, because reading a payload proves only what a token asserts about itself.
A JSON Web Token is three base64url segments joined by dots: header, payload, signature. This page splits them, decodes the first two, and shows you the JSON inside. Anyone holding a JWT can read everything it claims about itself. That's by design, and it's the first thing to understand about the format.
Decoding is not verification
The payload shown here is only what the token asserts. Nothing on this page tells you an issuer has vouched for it.
Anyone can build a token that says "role": "admin", base64url the pieces, staple any three characters on the end as a signature, and paste it here. It'll decode perfectly, because decoding only reverses an encoding. The signature is what separates a real token from a forged one, and checking it needs the issuer's secret or public key. This page doesn't have that key and won't ask you for it (it wouldn't accept one anyway).
The interface says so next to the result, and the same wording goes along with the copied output, so nobody can paste it into a ticket and mistake it for a validation. Verification belongs on your server, against the key from your identity provider's JWKS endpoint, using a library that also enforces the algorithm you expect. Don't skip that last part. Accepting whatever alg the token names is how the alg: none and RS256-downgraded-to-HS256 attacks work, and both were real breaks in real libraries.
The base64url difference, which used to break this page
JWT segments use the URL-safe alphabet from RFC 4648: - instead of +, _ instead of /, and the trailing = padding dropped, because tokens ride in URLs and Authorization headers.
The browser's atob doesn't accept that alphabet. Call it on a raw JWT segment and it throws InvalidCharacterError as soon as a - or a _ appears. Since those two characters stand in for two of sixty-four values, they show up in a large majority of real tokens. That's how this page used to behave: you'd paste a token from your own logs, get an error, and conclude the token was malformed.
The decoder now translates the alphabet, restores the padding, and reads the bytes as UTF-8, so a name claim containing an accented character or a non-Latin script comes back intact instead of as mojibake.
Reading the time claims
Three registered claims from RFC 7519 carry timestamps, and all three count seconds since the Unix epoch, not milliseconds. That factor of a thousand has confused a great many people at three in the morning. Each one is shown three ways: the raw number, the UTC ISO form, and a relative phrase in your local timezone.
iat: issued at. It tells you how old the token is and how long your lifetimes really are in practice.nbf: not before, the moment until which the token is invalid.exp: expires at, after which a correct verifier rejects it.
If a token has expired or isn't valid yet, the page flags it explicitly, which answers the question most people bring to a decoder.
What the header is telling you
The header names the algorithm in alg and often a key id in kid. HS256 is symmetric, meaning the same secret signs and verifies, so both parties hold it. RS256 and ES256 are asymmetric: the issuer signs with a private key and anyone can verify with the public one. kid tells the verifier which key from the JWKS to fetch, which is what makes rotation possible. And alg: none means an unsigned token, which some libraries once accepted.
A word about what you're pasting
A JWT is a bearer credential: whoever holds it can act as the subject named in it until it expires. Nothing you paste here is transmitted, and there's no network call in this code path at all. For this particular job, that's exactly why a local decoder beats the first search result. The token sits in sessionStorage for this tab only, and "Clear it now" removes it immediately.
To pull a base64url segment apart on its own, Base64 Encoder / Decoder handles the same alphabet. To reproduce an HMAC-SHA-256 signature when you do hold the secret, Hash Generator has an HMAC mode.
Frequently asked
Does a successful decode mean the token is genuine?
No, and this is the point worth internalising. Anyone can assemble a token claiming any role, staple arbitrary characters on as a signature, and it will decode here perfectly. Only signature verification against the issuer's key distinguishes a real token from a forged one, and that belongs on your server.
Why did other decoders reject my token as invalid?
JWT segments use the URL-safe alphabet, with hyphen and underscore standing in for plus and slash. The browser's atob throws on both characters, so a decoder calling it directly fails on the majority of real tokens. This one translates the alphabet and restores the padding first.
My token shows as not yet valid. What does that mean?
Its nbf claim sits in the future, so a correct verifier will reject it until that moment passes. In practice this almost always indicates clock skew between the issuing machine and yours rather than a problem with the token itself.
What should I look at in the header?
The alg value and the kid. HS256 is symmetric, so both parties hold the same secret; RS256 and ES256 are asymmetric, signed privately and verified with a public key. The kid tells a verifier which key to fetch, which is what makes rotation possible.