Paste a JWT into a decoder only when you are comfortable exposing that token to the tool. Decoding is simply base64url parsing of the header and payload; it does not check the signature. For production tokens, prefer a local debugger or a redacted fixture.
What a decoder can tell you
| Part | Useful fields | Not proof of |
|---|---|---|
| Header | alg, kid, typ | Which key is trusted |
| Payload | sub, iss, aud, exp | That the sender created it |
| Signature | Its presence | That it verifies |
const [header, payload] = token.split('.').slice(0, 2);
// Decoding these segments is inspection only.
A quick expiry check
exp is NumericDate: seconds since the Unix epoch, not JavaScript milliseconds.
const expired = payload.exp * 1000 <= Date.now();
That tells you why a client may receive an expiry error. It does not make an unverified payload trustworthy, and it does not replace an issuer/audience check.
Treat a JWT like a password while debugging. Logs, browser extensions, online decoders, and screen recordings are all places a bearer token can leak.
Verification has inputs a decoder can't provide
The correct server path is: pick keys from a configured issuer, allow only expected algorithms, verify the signature, then validate iss, aud, time claims, and application claims. A decoder is a microscope, not an access-control system.
Two header fields are the classic footguns. Never choose the verification algorithm from the token's own alg header — that's how alg: none or an RSA-to-HMAC confusion attack turns an attacker-supplied claim into a trusted session. Pin the allowed algorithm(s) in your service config instead. And never fetch the signing key from a jku or kid URL the token itself supplies; obtain keys from your configured issuer's key set, cache it, and refresh on a schedule rather than per-request.
Test the rejection cases, not just the happy path: expired token, wrong audience, wrong issuer, invalid signature, and alg: none. JWTs are transport containers, not a permission system — after verification, authorization still needs current server-side rules for the requested action.
