DevKit
Tester

JWT Signature Verify

Verify a JWT HS256/384/512 signature against a secret, locally.

Last updated: August 2026

Verifies HS256/HS384/HS512 signatures locally via Web Crypto. RS/ES algorithms are not supported here.

Share:

Was this tool helpful?

Checking a JWT signature, not just reading it

Decoding a JWT shows its claims; verifying proves those claims are trustworthy. An HS256/384/512 token is signed with HMAC using a shared secret. Verification recomputes the HMAC over header.payload with your secret and checks it matches the signature segment. If it matches, the token was issued by someone holding that secret and has not been altered.

The alg confusion trap

A notorious JWT vulnerability is trusting the alg field in the header. If a verifier blindly honors it, an attacker can set alg to none and strip the signature, or switch an RS256 token to HS256 and sign it with the public key as if it were an HMAC secret. A correct verifier fixes the expected algorithm in advance rather than letting the token dictate it.

Example

signing input = base64url(header) + "." + base64url(payload)
expected = HMAC-SHA256(secret, signing input)
valid = constant_time_equal(expected, token.signature)

Note this covers only the HS family. RS256 and ES256 tokens are verified with a public key, not a shared secret, so a secret-based check does not apply to them.

Signature valid is not the end

A matching signature still leaves the exp, nbf, issuer, and audience claims to check. A token can be perfectly signed and long expired. Pair this with the expiry checker and read raw claims with the decoder.

FAQ

Why does my valid token fail verification here? Usually the secret differs (a trailing newline or wrong encoding), or the token uses RS256, which needs a public key rather than a shared secret.

Is pasting my production secret safe? A local verifier keeps it in the browser, but a live signing secret is as sensitive as a private key. Prefer test secrets when experimenting.