Developer Tools All tools

JWT security checker

Paste a JSON Web Token and this page audits what the token says about itself: the algorithm named in the header, the parameters that tell a verifier where to fetch a key, how long the token stays valid, which registered claims are missing, and whether the payload is carrying anything that should not be readable. If you only want to see the claims, the JWT decoder prints them plainly; this page reads the same token and argues with it.

Paste a token above to audit it.

These are heuristics about the token's own contents, not a verification result. This page holds no key and makes no request, so it cannot tell you whether a signature is genuine, whether the issuer is who it claims to be, or whether your verifier is configured correctly. What it can do is read the header and the claims and point at the patterns that have caused real incidents. A token can pass every check here and still be forged.

Findings

Severity Finding Why it matters
Nothing audited yet.

Header

Payload

Your token stays in this tab. It is not uploaded, logged or stored — no cookie, no local storage, no history. Close the tab and it is gone.

What each finding is actually looking at

The header gets read first. An alg of none, or no alg at all, is the highest-severity result the page can produce, because it describes a token with nothing binding it to an issuer. An HMAC algorithm — HS256 and its relatives — is flagged one level down for a subtler reason: the same secret both makes and checks a signature, so every service that can verify the token can also mint one, and a public key published for RS256 becomes a usable HMAC secret if the verifier trusts the algorithm printed in the header.

Next come header parameters that carry a key or a route to one. jku and x5u are URLs whose hosts must be allow-listed; jwk embeds a public key that must not become trusted merely because the token supplied it. x5c is different: an embedded certificate chain can be safe when the verifier validates its path to a configured trusted root, checks its purpose and validity, and uses the leaf key to verify the signature. The kid value is checked separately for slashes, dot-dot segments, quotes and SQL keywords, because key ids are routinely concatenated into a file path or a lookup without anyone thinking about it.

The claims are then read as a set rather than one at a time. A missing exp outranks everything else in the payload, since a token with no expiry is a credential that only ends when the signing key does. Where exp and iat are both present the difference between them is the intended lifetime, and it is graded: under fifteen minutes is called out as good, over a day is a warning, over a month is serious. Missing aud, iss, sub and jti each get a finding at their own weight. Claim names are checked for passwords and keys, while string values are checked for recognizable card, identity-number and email shapes that have no business sitting in something anyone can read.

Why a token can pass this and still be broken

Almost every real JWT failure is a verifier failure, and a verifier is not something a web page can inspect. A token with a perfectly ordinary header is worthless if the service accepting it calls a decode function instead of a verify function, or verifies with an algorithm taken from the token, or fetches the key from the URL in jku, or checks the signature and then forgets to compare exp. None of that leaves a trace in the token itself, which is why this page can only argue about the half of the problem it can see.

The reverse is also true, and worth saying plainly: several of these findings are questions rather than faults. HS256 is the right choice inside a single service that both issues and consumes its own tokens. A missing aud is fine when exactly one service will ever see the token. A long lifetime is defensible for a machine credential rotated by other means. Severity here reflects how often a pattern has gone wrong in the field, not a judgement about your particular system, and a finding you can explain is a finding you can dismiss.

What the page will not do is imply more certainty than it has. There is no request, no key, no signature check and no attempt to guess the secret. The last row of every audit repeats that, because a security tool that lets you believe you have verified something is worse than no tool at all.

Questions people ask

Can this tell me whether my token is valid?

No. Validity means the signature matches a key you trust and the claims satisfy the rules of the service consuming the token, and this page has neither the key nor the rules. It reads the token, applies a list of heuristics to what it finds, and sorts the results. The only way to check validity is to verify the signature with the key on the server that trusts the issuer, using a library that lets your code choose the algorithm rather than reading it out of the header.

Why is HS256 flagged when every tutorial uses it?

Because tutorials build one service, and one service both issuing and verifying its own tokens is exactly the case where a shared secret is fine. The flag matters when the token crosses a boundary: hand an HS256 token to a second team, a partner, or a mobile client, and to verify it they need the secret that also lets them issue tokens as you. There is a second reason. If your verifier picks the algorithm from the header, an attacker can take your published RS256 public key, sign a token with HS256 using that key text as the secret, and be accepted. Choosing the algorithm in code rather than reading it from the token closes that, and asymmetric keys close the first problem properly.

Does a missing aud claim really matter?

It matters as soon as more than one service trusts the same issuer, which happens earlier than most teams expect. Without aud, a token that a user hands to a low-value internal service can be lifted from that service's logs and replayed against the billing API, because both accept anything the identity provider signed. The aud claim names the intended recipient and the recipient checks it, which turns a general-purpose credential back into a specific one. Adding the claim without checking it achieves nothing at all, so verify both halves.

How short should an access token's lifetime be?

Short enough that a leaked token stops working before anyone can use it, which in practice means five to fifteen minutes for a browser or mobile client. The usual objection is that users would be logged out constantly; the usual answer is a refresh token, which is long-lived, stored more carefully, and can actually be revoked because the issuer checks it against a store on every use. That split is the whole point — the credential travelling on every request is disposable, and the credential that is hard to replace never travels. Machine-to-machine tokens can be longer if the rotation and revocation story is genuinely better, but "our tokens last a year" is almost never the result of that reasoning.

The audit says my payload contains personal data. What should I do?

Take it out, and treat the tokens already issued as leaked. A signed JWT is base64url, which is an encoding and not a cipher, so anything in the payload has already been readable by the browser storing it, every proxy it passed through, and every log line that captured the Authorization header. The usual replacement is an opaque identifier in the token and an API call that returns the details to a caller that has proved it is allowed to have them. If the data genuinely has to travel inside the token there is JWE, the encrypted variant — but the honest first question is why a credential is being used to carry a record at all.