Nimble Toolbox

Decode and verify a JWT

Paste an access token or an ID token and its header and payload appear below, with the time claims resolved to dates. Add the signing key, or the issuer’s whole JWKS, and it checks the signature too. All of it happens in your tab.

How to use it#

  1. Paste the token, including all three dot-separated parts. Bearer in front, or the whole Authorization header line, is fine.
  2. Read the header and payload. Beside them, the figures give the issue and expiry times and say whether the token is still valid.
  3. Copy the header or the payload from the button beside its caption.
  4. To check the signature too, paste the signing key: a shared secret for HS256, or a public key for RS256 and ES256. A whole JWKS works, and Key used says which key in it was used.

A JWT is encoded, not encrypted#

The three parts of a token are separated by dots and the first two are base64url, which is an encoding rather than a cipher. Anyone holding the token can read the payload, including in a browser console, without any key at all. That is what this page does.

It follows that a JWT payload is the wrong place for anything private. Email addresses, internal user ids, role names, and account status are all routinely put there, and all of them are readable by whoever holds the token, which on a web app usually includes the end user.

The signature is the part that carries trust. It proves the payload has not been altered since the issuer produced it, and checking it requires the key the issuer signed with. Paste that key into the Signing key box, under the decoded token, and this page will check it with the browser’s own crypto, not a server.

Why pasting a token into a website is a real risk#

A JWT is usually a live credential. Anyone holding it can act as the user it identifies until it expires, and expiry is frequently measured in hours. A token that reaches a server hands that server a working session.

From the outside, a page that decodes in your browser looks exactly like one that sends the token away. This page does the decoding in JavaScript in your tab, which you can confirm by opening your browser’s network panel and watching nothing happen when you paste.

If a token has already been pasted somewhere you are unsure about, the fix is to revoke or rotate it rather than to hope. Tokens are cheap to reissue and a leaked one is not something you can take back.

Verifying against a JWKS#

Issuers that sign with RS256 or ES256 publish their public keys as a JWKS, a JSON document with a keys list, usually at a URL ending in /.well-known/jwks.json. You can paste that whole document into the key box rather than digging out the one key you need.

The token header decides which key is used. Its kid field names a key, and only the key in the set with that kid is tried, as a real verifier would. If no key has that kid, the page says so and lists the kids the set does have, which usually means the issuer has rotated its keys and the token or the set is out of date. If the token has no kid, every key in the set that fits the algorithm is tried, and the page names the one that matched. The Key used row says which reading applied.

The claims worth reading first#

Three registered claims hold times, all of them in seconds since the Unix epoch rather than milliseconds: iat when the token was issued, nbf the point before which it should be rejected, and exp when it stops being valid. This page resolves all three to dates and says whether the token is currently inside that window.

The header is worth a glance too. Its alg field names the signing algorithm, and a token arriving with alg set to none is the classic attack: it asks the receiving system to accept an unsigned token as though it were signed. Any library written in the last several years rejects that, but it is still the first thing to look at when a token behaves strangely.

Frequently asked questions#

What do I need to verify a signature?

#

The key the token was signed with. For the HS algorithms that is the shared secret, which is a live credential; for RS, PS, and ES it is the issuer’s public key, which is not secret and is usually published at a JWKS endpoint. Paste the key, or the whole JWKS, into the key box and the check runs in your tab. Leave it empty and the token is only decoded, which proves nothing about who issued it.

How do I check whether a JWT has expired?

#

Paste it. The exp claim is read as a date in UTC, with how long ago it passed or how long is left, and the status line says whether the token has expired, is not valid yet, or is inside its window. The comparison uses your own clock, so a device that is a few minutes out can give the wrong answer for a token right at its expiry.

Can I paste the Authorization header as it is?

#

Yes. A token copied from a request usually arrives as Bearer followed by the token, sometimes with Authorization: in front. Both are left out before decoding, so you do not have to trim them yourself. The same goes for the signature check.

Is it safe to paste a signing secret here?

#

The check uses the Web Crypto API in this tab and the secret goes nowhere, which you can confirm in your network panel: paste, and watch that no request goes out. Even so, a signing secret can mint tokens for anyone, so a test key, or one you can rotate, is the better habit. If a secret has already gone somewhere you are unsure about, rotate it. Public keys carry no such risk, so paste those freely.

Can I paste a whole JWKS?

#

Yes. Paste the JSON with its keys list and the key whose kid matches the token header is used. When no key has that kid, the check fails and the page lists the kids the set holds. When the token has no kid, every key that fits the algorithm is tried and the one that matched is named. Several keys sharing one kid are all tried the same way.

Is my token sent anywhere?

#

No. The decoding is plain JavaScript running in this tab. You can verify it by opening the network panel in your browser’s developer tools and watching for requests while you paste, because there will not be any.

Can I decode an encrypted token?

#

No. This page reads JWS tokens, which are signed and readable. A JWE token is genuinely encrypted, has five parts rather than three, and cannot be read without the decryption key.

Why does the expiry look like it is in 1970?

#

The claim was probably written in milliseconds. The specification says these are seconds since the epoch, so a millisecond value is a thousand times too large and a seconds value read as milliseconds lands just after 1970. The fix belongs in whatever issued the token.

Is it safe to put user data in a JWT?

#

Only data you are content for the user and anyone holding the token to read. The payload is encoded rather than encrypted. Keep anything sensitive server-side and reference it by an identifier instead.