Verify JWT Signatures in Your Browser
Paste a JSON Web Token plus its HMAC secret or public key. This tool recomputes the signature with the browser's native WebCrypto API and tells you whether the token is authentic, expired, or not yet valid — with nothing ever sent to a server.
Enter the shared secret used to sign the token. Signature verification runs live as you type.
Decoded Header
—
Decoded Payload
—
Checks
- …Paste a token to begin.
How the verification works
A JWT is three Base64URL segments joined by dots: header.payload.signature. The first two segments together form the signing input. The signature is a MAC or digital signature computed over exactly that byte string: ASCII(base64url(header) + "." + base64url(payload)).
For HMAC algorithms (HS256/384/512) the signature is HMAC-SHA(secret, signingInput). This tool imports your secret as a raw CryptoKey, recomputes the HMAC, and compares it byte-for-byte against the decoded signature. HMAC is symmetric, so the same secret both signs and verifies — anyone holding it can forge tokens, which is why you never verify a bare Base64 blob without checking the MAC first.
For RS256 (RSASSA-PKCS1-v1_5 over SHA-256) and ES256 (ECDSA on P-256 over SHA-256), verification is asymmetric. You supply only the public key — as PEM/SPKI or a JWK — and crypto.subtle.verify() checks the signature mathematically without ever needing the private key. ES256 signatures in JWTs use the raw r‖s IEEE-P1363 layout that WebCrypto expects directly.
Beyond the signature the tool Base64URL-decodes the registered claims and validates timing: exp (expiry) and nbf (not-before) are compared against the current Unix time, and iat is surfaced. A token can carry a perfectly valid signature and still be unusable because it expired or is not yet active — so a green signature and a green clock are separate checks. Everything runs locally; the comparison uses a length-safe constant-time loop to avoid leaking timing information about the expected MAC.