DevKits

JWT Verifier — Validate JWT Signatures Online (HS / RS / PS / ES)

Paste a JWT and its signing key (HMAC secret, RSA/EC public key in PEM or JWK) to verify the signature and inspect claims. Supports HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512. Also flags exp / nbf / iat time-based claims. 100% local — nothing is sent to any server.

Last updated:

Comments

Paste a JWT and the matching key (HMAC secret or RSA/EC public key in PEM/JWK). The tool verifies the signature, decodes the claims, and flags expired or not-yet-valid tokens. Runs 100% in your browser via the Web Crypto API — no upload.

Signature verification runs entirely in your browser via the Web Crypto API. Supports HS/RS/PS/ES × 256/384/512. Need to generate a JWT? JWT Generator.

What is JWT Verifier?

A JWT Verifier answers one question your JWT Decoder can't: is this token actually authentic? Decoders can show you the payload of any Base64URL string; verifiers cryptographically prove the payload was signed by the holder of a specific key and hasn't been tampered with. That's the difference between reading the header of a letter and confirming the wax seal — one is trivial, the other is what makes JWTs a security primitive.

How to verify a JWT signature

  1. 1Paste the full three-segment JWT (header.payload.signature) into the token field.
  2. 2The tool auto-detects the alg from the header — HS256, RS256, ES256, PS256, etc.
  3. 3Paste the matching key: an HMAC secret for HS*, an SPKI PEM (-----BEGIN PUBLIC KEY-----) or JWK for RS*/PS*/ES*.
  4. 4Signature valid ✅ / invalid ❌ shows immediately, together with decoded header + payload.
  5. 5Time-based claims (exp, nbf, iat) are validated separately and shown as informational badges — an expired token can still be crypto-valid.

Use Cases

Debug 401 Unauthorized responses

Your API returns 401 but the token looks fine in a decoder. Paste it here with your service's public key — either the signature is bad (key rotation, wrong tenant, tampering) or a claim like exp/aud/iss is failing.

Test a new signing pipeline

You just switched from HS256 to RS256. Generate a token, paste it here with the new public key, and confirm the switch works before deploying.

Validate third-party issued tokens

Fetch the issuer's public key from /.well-known/jwks.json and verify tokens against it — the same check your API gateway performs, but interactive.

Catch the alg="none" attack

Confirm your library rejects tokens whose header claims alg="none". This tool always flags them as invalid regardless of payload — matching the RFC 7518 requirement.

Code Examples

Verify HS256 in Node.js (jsonwebtoken)

import jwt from "jsonwebtoken";

try {
  const decoded = jwt.verify(token, "your-256-bit-secret", { algorithms: ["HS256"] });
  console.log(decoded);
} catch (err) {
  console.error("Invalid token:", err.message);
}

Verify RS256 with a public key

import jwt from "jsonwebtoken";
import fs from "node:fs";

const pub = fs.readFileSync("public.pem");
const decoded = jwt.verify(token, pub, { algorithms: ["RS256"] });

Verify with PyJWT

import jwt

decoded = jwt.decode(token, key, algorithms=["RS256"], audience="my-api")

Verify in Go (golang-jwt/jwt v5)

import "github.com/golang-jwt/jwt/v5"

token, err := jwt.Parse(raw, func(t *jwt.Token) (any, error) {
    if _, ok := t.Method.(*jwt.SigningMethodRSA); !ok {
        return nil, fmt.Errorf("unexpected alg: %v", t.Header["alg"])
    }
    return publicKey, nil
})

Key Concepts

Signature vs. claims
Signature verification proves who signed the token. Claim validation (exp/nbf/aud/iss/sub) proves the token is being used correctly. Both must pass for a token to be trusted — a valid signature on an expired token is still expired.
SPKI PEM
The `-----BEGIN PUBLIC KEY-----` format. This is what verifiers need. The other common format, `-----BEGIN RSA PUBLIC KEY-----` (PKCS#1), is not accepted by Web Crypto directly — convert with `openssl rsa -pubin -in pkcs1.pem -RSAPublicKey_in -out spki.pem`.
JWK Set (JWKS)
A JSON document at `/.well-known/jwks.json` containing multiple public keys with `kid`s. Your verifier picks the key whose `kid` matches the token header's `kid`. Enables key rotation without redeploying clients.
alg="none"
A special algorithm that means "no signature." Historically accepted by naive verifiers, letting attackers strip signatures and forge tokens. RFC 7518 §3.6 requires rejecting it whenever signature verification is on.

Tips & Best Practices

  • ▸The key type must match the alg. HS256 wants a raw string; RS256 wants an RSA public key; ES256 specifically wants a P-256 EC public key (P-384/P-521 for ES384/ES512).
  • ▸If you're building auth in production, always pass an explicit `algorithms` allowlist to your verify() call — this shuts down algorithm-confusion attacks like RS256→HS256.
  • ▸Use `iat` (issued-at) to detect replay: reject tokens whose `iat` is older than your access-token TTL, even if `exp` says they're still valid.
  • ▸Clock skew matters. Allow a small `leeway` (30-60s) for `exp` and `nbf` checks to survive minor server time drift.

Frequently Asked Questions

What does this tool actually check?

Three things: (1) the signature is mathematically valid for the given key and algorithm, (2) the alg header matches a supported algorithm — including flagging the classic 'alg: none' vulnerability, (3) the standard time claims exp (expired?), nbf (not yet valid?), and iat (issued in the future?). Time checks are informational — an expired token still shows as signature-valid if the crypto is correct.

What key should I paste?

It depends on the algorithm in the JWT header. For HS256/384/512, paste the raw shared secret string used to sign it. For RS256/384/512 or PS256/384/512, paste the RSA public key in SPKI PEM (-----BEGIN PUBLIC KEY-----) or JWK format. For ES256/384/512, paste the EC public key (also SPKI PEM or JWK, with the right curve for the algorithm: ES256→P-256, ES384→P-384, ES512→P-521).

Why does verification fail even though I have the right key?

Common causes: (1) The key you pasted is the private key instead of the public key — this tool needs the public key for RS/PS/ES. (2) Curve mismatch — ES256 requires P-256 exactly, using a P-384 key gives an invalid signature. (3) The token was tampered with after signing. (4) Copy-paste added whitespace or missing BEGIN/END markers. Look at the specific error message; the Web Crypto API's messages are usually precise.

Is my key sent to any server?

No. Verification runs entirely in your browser via crypto.subtle.verify. You can confirm with DevTools Network panel — no request fires when you paste a token. That said, don't paste production secrets or private keys into any online tool you can't fully inspect — the source is available on GitHub if you want to audit.

Why is alg="none" flagged as invalid?

Historically, some JWT libraries accepted tokens with alg="none" (unsigned) as valid — an attacker could strip the signature and the server would trust the payload. RFC 7518 requires that unsigned tokens MUST NOT be accepted when signature verification is enabled. This tool always flags alg="none" as invalid regardless of the payload.

Try Next

AES Encrypt / Decrypt

Encrypt and decrypt text with AES (128 / 192 / 256, GCM authenticated or CBC legacy) using a password. PBKDF2 key derivation with 200,000 iterations. 100% local — the Web Crypto API runs entirely in your browser.

Related Tools

Reference & Guides