JWT Debugger

Decode and inspect JSON Web Tokens securely in your browser

Privacy Notice: All decoding and signature verification happens in your browser. No token or key is sent to any server.

How to Use

  1. Paste a JWT — decoding happens locally as you type
  2. Inspect header, payload, and the "Claims Explained" breakdown
  3. Check the exp / iat / nbf status badge
  4. Under Signature Verification, paste the shared secret (HS*) or public key (RS/ES/PS) to confirm the signature — the result updates live
  5. Copy the decoded JSON if you need it elsewhere

Decoding is not verification. Anyone can read a JWT — a signature check is what proves it's authentic and untampered.

How to Verify a JWT Signature

A JWT's signature is computed over the base64url-encoded header.payload using the algorithm named in the header's alg field. Verifying means recomputing (or, for public-key algorithms, cryptographically checking) that signature with the correct key. There are two families:

  • Symmetric (HMAC — HS*). The same shared secret both signs and verifies. Paste that secret into the Signature Verification box. Because whoever can verify can also forge, secrets never leave your own systems — never publish them.
  • Asymmetric (RSA / ECDSA / RSA-PSS — RS*, ES*, PS*). A private key signs; the matching public key verifies. Paste it as a PEM public key (SPKI), an X.509 certificate, a single JWK, or a full JWKS — the JSON document OIDC providers serve at their JWKS endpoint. If you paste a JWKS, the matching key is picked automatically by the token's kid.

This tool verifies these standard JWA algorithms (RFC 7518) entirely in your browser:

Family Algorithms Key
HMACHS256, HS384, HS512Shared secret
RSA (PKCS#1 v1.5)RS256, RS384, RS512Public key (PEM)
ECDSAES256, ES384, ES512Public key (PEM)
RSA-PSSPS256, PS384, PS512Public key (PEM)

The spec also defines EdDSA (Ed25519/Ed448) and none. A token with alg: none carries no signature and should be rejected outright in production.

The JWT Mistakes We See in Real Codebases

  • alg: none accepted by the verifier. RFC 7519 allows an "unsecured" JWT (no signature). Several libraries historically trusted it by default, which turns any user-controlled token into an admin token. Fix: set an explicit algorithm allow-list (["RS256"]), never pass the alg from the token header into your verify call. CVE-2015-9235 and the Auth0 advisory are the canonical writeups.
  • HS256 vs RS256 confusion. If the verifier will accept either and you publish your RSA public key (as OIDC requires), an attacker can sign an HS256 token using your public key as the HMAC secret and pass verification. Fix: pin the algorithm, don't "auto-detect" from the header.
  • Clock-skew off-by-one on exp. exp is a Unix timestamp in seconds (RFC 7519 §4.1.4). Two services whose clocks disagree by even 30 seconds will reject tokens that should still be valid. Fix: allow a small leeway (most libraries call it clockTolerance) of 30–60 seconds, and run NTP on every host.
  • Missing kid and no key rotation. Without a kid (key ID) in the header, your verifier has to guess which key signed a token. You can't rotate without downtime. Fix: include kid, publish a JWKS endpoint, and treat signing keys like any other secret — 90-day rotation is a reasonable default.
  • Skipping aud and iss validation. A token issued for service A will happily verify against service B's endpoint if both trust the same IdP and neither checks audience. This is the single most common "the signature was valid but auth was still broken" bug teams hit.