JWT Debugger
Decode, verify, sign, and audit JWTs — locally
Everything, including signature verification and signing, runs in your browser. Your token, secret, and keys are never uploaded or stored on a server.
The JWT Decoder on this site deliberately stops at decoding, because verifying a signature means asking for a secret or a key, and that's not something a paste-and-view tool should do. This tool exists for when you actually need that: paste a token and a public key or secret and find out if the signature is real, sign your own test token to see how a library on the other end would receive it, or work out exactly which check is failing when a server rejects a token that looks fine to you. Every check, every verify, and every signature, runs in your browser. Nothing you paste, including a secret or a private key, is ever sent anywhere.
JWT structure and base64url
A JWT is three parts joined by dots: header.payload.signature. The header and payload are JSON, each Base64url-encoded, which is the same idea as ordinary Base64 but swaps + and / for - and _ so the result can sit safely inside a URL or an HTTP header without extra escaping. Base64url encoding isn't encryption. Anyone holding the token can decode the header and payload in one step, which is exactly what the JWT Decoder does.
The signature is different. It isn't JSON and it isn't meant to be decoded and read, it's a fixed-length block of bytes produced by running the header and payload through a signing algorithm with a key. That's the part this tool actually checks.
Verifying signatures: HS vs RS/ES
HS256, HS384, and HS512 are HMAC algorithms: the same secret both signs the token and verifies it. Whoever issues tokens and whoever checks them have to share that one secret, which means anything that can verify a token can also forge one. That's fine inside a single service you control, and a real liability the moment a third party needs to check your tokens, because now they're holding your only signing secret too.
RS256/384/512, PS256/384/512, and ES256/384/512 are asymmetric: a private key signs, and a completely different public key verifies. You can hand the public key to anyone who needs to check your tokens, and even if they leak it, they still can't forge a new one, since forging needs the private key. RS and PS are both RSA-based (PS uses a more modern padding scheme); ES is elliptic-curve, which gets you a comparable security level with a much shorter key. EdDSA is a newer elliptic-curve scheme with similar properties, supported here where the browser's crypto implementation allows it.
- This tool always keeps the two directions of key separate: Decode & Verify takes a public key or shared secret, Build & Sign takes a private key or shared secret. Pasting the wrong one for the alg produces a specific error, not a silent failure.
Reading exp, nbf, iss, aud — and why tokens get rejected
A valid signature only proves a token wasn't tampered with. It says nothing about whether the token should be accepted right now, for this request. That's what the standard claims are for. exp and nbf bound the token to a window in time. iss says who issued it, so a service can refuse tokens from an issuer it doesn't trust. aud says who the token is for, which stops a token meant for one API being replayed against another.
Rejection Diagnostics runs each of these independently: expected issuer, expected audience (aud can be a single string or a list, and it checks either shape), expected algorithm, and a clock override for testing exp/nbf against a time other than right now. Every check that has an input runs and reports its own pass or fail, so a failing exp doesn't hide a mismatched aud sitting right behind it.
Common JWT security mistakes
A handful of mistakes account for most real-world JWT vulnerabilities:
- alg: none — some early libraries treated this as "unsigned, trust it anyway." A token with alg: none is not signed at all and must always be rejected outright.
- Algorithm confusion — if a server blindly trusts the alg in the token's own header, an attacker can take a token meant to be RS256, switch the header to HS256, and sign it using the RS256 public key as if it were an HMAC secret. The fix is to always tell your verification library which algorithm you expect, never let the token pick.
- Weak HMAC secrets — an HS256 secret that's a dictionary word or a copy-pasted example (your-256-bit-secret shows up constantly) can be brute-forced offline once an attacker has one valid token to test guesses against.
- No expiry — a token that never expires is a permanent credential the moment it leaks.
The Security Scan panel checks the first, third, and fourth of these directly against the token you paste, and explains the second as guidance rather than claiming to have found it, since that one can't be confirmed from a single static token.