Decode a JWT and check its signature in your browser
Paste a token into the box and its header and payload are decoded on the spot, with exp, iat and nbf turned into readable dates and one sentence saying whether it has expired. Decoding is only base64 and proves nothing, so the signature is a separate step: paste the shared secret for HS256, or the issuer's public key or JWKS for RS256 and ES256, and the page tells you whether it actually matches.
Decode a JSON Web Token
Paste a token below. It is decoded here, on your own machine, by the page you are already looking at. Nothing is sent anywhere, nothing is written to this browser’s storage, and the token never goes near the address bar, so it cannot end up in your history or your browser’s sync.
Nothing you paste here is uploaded. The whole tool runs inside this tab, on your machine.
JWT decoder, step by step
- Paste the tokenStraight out of wherever you found it. A leading Bearer, the quotes around it and any line breaks the terminal added are all stripped before anything is decoded.
- Read the header, the payload and the datesThe three timestamp claims come back as dates in your own time zone, with a sentence saying whether the token has expired and by how long, so nobody has to convert an epoch by hand.
- Check the signature, if you have the keyPaste the shared secret for an HS token, or the public key or a whole JWKS for an RS or ES one. Until you do, the page says the token is decoded and not verified, because that is what it is.
Base64 for the reading, WebCrypto for the checking, and nothing at all for the sending
Decoding a JWT is not cryptography. The first two parts are base64url, so reading them is a string operation that any page can do to any token, which is why so many sites will happily do it for you and why doing it on somebody else's server is such a bad habit. The signature is the part that means something, and it is checked here with WebCrypto, the signing and verification built into the browser itself: HMAC for the HS family, RSASSA-PKCS1-v1_5 and RSA-PSS for RS and PS, and ECDSA for ES. A pasted JWKS is used as text, and the key is chosen by matching the kid in the token's header. What the page will not do is fetch that key set from its URL, because a convenience request is still a request, and one going out of a tab holding a production token is the whole thing this page is arguing against.
People paste production tokens into jwt.io every day. It is a good site and there is no suggestion it does anything wrong, but the habit is the problem rather than the destination: a bearer token is a password with an expiry date on it, and putting one into a text box on somebody else’s server is the same shape of mistake as pasting a password there. Most of the time the token is already expired and nothing comes of it. The one time it is not, you have handed out a live credential for whatever the token was minted to reach.
This page does the same job in the tab you already have open. The decoding is a few lines of base64, the signature check is the browser’s own crypto, and neither of them needs a server, so there is not one. That is not a privacy feature bolted on afterwards; it is what the tool is, because the job never needed anything else.
The other half of it is that decoding a token tells you almost nothing. Every free decoder shows you a payload and a green tick and leaves you to work out that the tick refers to the JSON parsing rather than the signature. Here they are two different blocks with two different vocabularies: the token is decoded, and separately it is checked, and until you have given it a key to check against the page says so in as many words.
Questions
Does my token get sent anywhere?
No. The decoding is a base64 operation done by the page you are looking at, and the signature check is done by your browser's own crypto. There is nothing in this tool that makes a request, and the token is never written to storage, to a cookie, or to the address bar where it could reach your history.
What is the difference between decoded and verified?
Decoding is reading. Anybody can decode any token, including one somebody made up a minute ago, because the header and payload are only base64. Verifying is checking the signature against a key, which is the part that says the token really came from the issuer it names. This page keeps them in separate blocks and never uses the word valid.
Which algorithms can it check the signature for?
HS256, HS384 and HS512 against a pasted secret, and RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384 and ES512 against a pasted public key or JWKS. Anything else is reported as something this page cannot check rather than as a signature that failed, because those are very different things to be told.
Can it fetch my JWKS from its URL?
No, and that is deliberate rather than unfinished. Fetching a key set means a request naming the issuer whose production token you are currently holding, out of a page whose entire pitch is that it makes no requests. Paste the JSON instead; the key is picked out of it by matching the kid in the token header.
Why does it make such a fuss about alg none?
Because a token declaring alg none carries no signature at all, so anybody who can send it can also write a replacement saying whatever they like. Libraries have shipped with that case quietly accepted more than once. A decoder that renders it like any other token is teaching the wrong lesson, so this one says so in as many words and refuses to call it verified.
Other things here
There is a full list on the free tools page. They all work the same way: in the browser, with nothing to install.
The tool is free. So is the thought.
This page did one small job. Edmund is for the thing you thought of while doing it: a capture app for iPhone, iPad and Mac that files a note the moment you have it, so it does not get lost between having it and writing it down.
See what Edmund does