DevKitHub

API & Security

JWT Signature Verifier — Check an HS256 Token

Paste a token and its signing secret to check whether the signature is genuine. Both stay on your machine — there is no endpoint here that could receive a secret.

0 lines

This tool runs entirely in your browser. Your input is never uploaded, stored or logged.

How it works

Decoding a JWT proves nothing. The payload is base64, not encryption, and anyone can rewrite it and re-encode it; the signature is the only part that establishes the token came from somewhere holding the key. Verification is therefore the step people actually want, and almost no free tool offers it, because offering it means being sent a signing secret. That is precisely why it belongs in a browser-only tool: the HMAC is computed here, the secret never leaves the machine, and there is deliberately no API endpoint that could receive one.

HMAC is implemented as RFC 2104 defines it, including the part that is easy to miss — a key longer than the 64-byte block size is hashed down first, and skipping that makes every long secret silently fail to verify. The comparison is constant-time. Not because a timing attack is plausible against a page running on your own machine, but because this is the comparison people copy into their own verification code, and the fast version is the one that leaks.

Algorithms it cannot check are reported as unchecked rather than as invalid, by name. Telling somebody their signature is wrong when the truth is that you never verified it is the worst available answer. RS256 and ES256 are asymmetric and need a public key; HS384 and HS512 need hash functions this package does not implement. In each case the report says which, and warns about the RS256-to-HS256 confusion attack — where an attacker re-signs a token using the public key as an HMAC secret, and a library that trusts the header’s declared algorithm accepts it.

Common problems

Every example below is run against this tool in our test suite, so what it says here is what the tool actually does.

A JWT has three dot-separated parts and this has 2.

a.b
Why:
A two-part token is an unsecured JWT with no signature at all. More than three parts is usually a JWE, which is encrypted rather than signed and cannot be verified with a secret.
Fix:
Check what produced the token. A JWE needs decryption, not verification.

The header is not valid base64url-encoded JSON.

!!!.eyJzdWIiOiIxIn0.x
Why:
The first segment is not a base64url JSON object. Usually the token was truncated, or standard base64 was pasted where base64url was expected — the two differ in two characters.
Fix:
Re-copy the whole token. JWTs use base64url: - and _ rather than + and /.

A long secret verifies everywhere except here.

Why:
A key longer than 64 bytes must be hashed before use, per RFC 2104. An implementation that skips that step disagrees with every correct one on long secrets.
Fix:
Nothing to do here — this hashes long keys correctly. If your own code disagrees, that is where the bug is.

Frequently asked questions

Is my signing secret sent anywhere?
No. The HMAC is computed in your browser and there is no API endpoint on this site that accepts a token or a secret — that absence is asserted by a test. It is the only reason a tool like this can responsibly exist.
Why can it not verify RS256?
RS256 is an asymmetric signature verified against a public key rather than a shared secret. It is reported as unchecked rather than invalid, because saying a signature is wrong when you never checked it is worse than saying nothing.
What is the RS256-to-HS256 confusion attack?
An attacker takes a token signed with RS256, changes the header to HS256, and re-signs it using the public key as the HMAC secret. A library that verifies with whatever algorithm the header names will accept it. Pin the algorithms you accept instead of trusting the token.

Last updated