JWT Signature Verifier
Decoding a JWT Is Not Verifying It
Reading a JSON Web Token is trivial: the header and payload are base64url-encoded JSON that anyone can decode without a key. That is what our JWT decoder does, and it is the right tool when you simply want to see what is inside a token. Verification is a different operation entirely. It asks a cryptographic question — was this exact byte sequence signed by the private key belonging to the issuer I trust? — and only a signature check can answer it.
The distinction matters because it is one of the most common security defects in real authentication code. Most JWT libraries expose both a decode function and a verify function, and the two names look interchangeable to a developer in a hurry. They are not. Calling decode in a request handler means an attacker can craft a token containing any claims they like — "role": "admin", "sub": "someone-else" — and your service will believe it, because nothing ever checked who wrote it. Decoding is for debugging and for reading claims out of a token you have already verified.
How This Verifier Works
The signing input of a JWS is the first two segments joined by a dot: base64url(header) + "." + base64url(payload). The signature in the third segment covers exactly those bytes. This tool reconstructs that string, imports your public key through the Web Crypto API, and asks the browser's own cryptographic implementation whether the signature matches. Nothing is transmitted; the verification happens in the same JavaScript sandbox as the page.
Because the signature covers the encoded header, tampering with any byte of the header or payload invalidates it. This is worth seeing for yourself: load the working example, verify it, then change a single character in the payload segment and verify again. The result flips to invalid immediately.
Supported Algorithms
| Algorithm | Family | Key required | Notes |
|---|---|---|---|
| RS256 / RS384 / RS512 | RSASSA-PKCS1-v1_5 | RSA public key | The default for OpenID Connect and most identity providers |
| PS256 / PS384 / PS512 | RSA-PSS | RSA public key | Randomised padding; preferred over RS* for new systems |
| ES256 / ES384 / ES512 | ECDSA | EC public key | Much smaller signatures; ES512 uses curve P-521, not P-512 |
A detail that trips people up: the number in an ECDSA algorithm name refers to the hash, and the curve does not always match it. ES512 means SHA-512 over curve P-521. There is no P-512.
Why HMAC Algorithms Are Not Supported
HS256, HS384, and HS512 are symmetric: the same secret both signs and verifies. Verifying an HMAC token in a browser page would mean pasting your production signing secret into a web form, and a secret that has been pasted into any web page should be treated as compromised and rotated. That trade is not worth it for a debugging convenience, so this tool deliberately refuses HMAC tokens rather than quietly encouraging the habit.
Public keys carry no such risk. An RSA or EC public key is published at a JWKS endpoint precisely so that anyone can fetch it — pasting one here discloses nothing that is not already public.
PRIVATE KEY and JWKs containing a private exponent, but the discipline matters more than the guard rail. If you need to test HMAC verification, do it in a local script where the secret never leaves your machine.
The Algorithm Confusion Attack
The most instructive JWT vulnerability comes from trusting the token to describe how it should be checked. A verifier that reads alg from the header and dispatches on it can be attacked in two ways. The first is alg: "none", a legal value meaning unsigned; a naive implementation happily accepts a token with an empty signature. The second is subtler: an attacker changes RS256 to HS256 and signs the token using the issuer's public key as the HMAC secret. Because the public key is public, the attacker can compute a valid HMAC, and a verifier that dispatches on the header will validate it.
The defence for both is identical, and it is a single sentence: your server decides which algorithm is acceptable, and rejects everything else. Never let the token choose. This tool reports the algorithm it found and refuses alg: none outright, but in your own code the algorithm must be pinned in configuration.
Reading the Claim Checks
A valid signature is necessary but not sufficient. A token can be perfectly signed and still unusable because it expired last week, or because it was minted for a different service. The claim panel checks the four things a complete verification should check:
exp— the expiry, a Unix timestamp in seconds. A 60-second clock skew allowance is applied, matching common library defaults. To inspect a rawexpvalue on its own, our Unix timestamp converter renders it as a readable date.nbf— not before. A token minted on a machine whose clock runs fast can fail this check while being entirely legitimate.iss— the issuer. Supply the value you expect and it is compared exactly. Accepting a signature from any issuer whose key you happen to hold is a real vulnerability in multi-tenant systems.aud— the audience, which may be a string or an array. A token minted for a different audience must be rejected even when the signature is valid.
Working With JWKS Key Sets
Identity providers publish their public keys as a JSON Web Key Set at a well-known URL, typically /.well-known/jwks.json. A key set holds several keys so the issuer can rotate signing keys without downtime, and the token's kid header names which one was used. Paste an entire JWKS here and the matching key is selected automatically by kid.
An unknown kid is the single most common cause of sudden verification failures in production. It almost always means the issuer rotated its key and your service is holding a stale cached copy of the key set. The fix is to re-fetch the JWKS when an unrecognised kid appears, with a sensible rate limit so a malformed token cannot trigger a fetch storm. To pull individual keys apart or convert one to PEM, use our JWKS decoder.
When Verification Fails Unexpectedly
- The
Bearerprefix was not stripped. AnAuthorizationheader isBearer <token>. This tool strips it for you; many libraries do not. - Whitespace from copy and paste. A trailing newline changes the signing input and therefore the signature.
- An X.509 certificate was supplied instead of a public key. Extract the key first with
openssl x509 -pubkey -noout -in cert.pem. - The wrong key format. SPKI (
BEGIN PUBLIC KEY) is what Web Crypto expects. A PKCS#1 block (BEGIN RSA PUBLIC KEY) needs conversion first. - Clock skew. If signature verification passes but
nbffails on a freshly issued token, the issuing and verifying machines disagree about the time. Run NTP.