devtools

JWT Decoder

Decode a JWT to read its header and payload without sending it anywhere. See the algorithm, expiry and issued-at times — and why decoding is not verifying.

Runs entirely in your browser — your data never leaves your device.

How to use JWT Decoder

What it does & when you need it

You've got a JWT from an Authorization: Bearer header, a cookie, or a login response, and you need to see what's inside — which user, which scopes, when it expires — without pasting a production credential into a random website. This decoder splits the token, Base64URL-decodes the header and payload locally, and shows the claims plus a human-readable expiry. Nothing is transmitted; the whole thing runs in your browser.

How to use

  1. Paste the token into the jwt buffer, or press Sample to load an example. A JWT has three parts separated by dots: header.payload.signature.
  2. The decoded header and payload appear as formatted JSON. The Registered claims panel translates iat, nbf, and exp into UTC dates and flags whether the token is expired or not yet valid.
  3. Use Copy payload (or Ctrl/Cmd + Enter) to copy the claims.

Things worth knowing

Decoding is not verifying — this is the one thing to internalise. A JWT is signed, not encrypted. The payload is just Base64URL-encoded JSON that anyone can read, and decoding it tells you nothing about whether it's authentic. A token with a tampered payload still decodes perfectly here. To trust a token you must verify its signature against the issuer's secret (HS256) or public key (RS256/ES256) — a step this tool deliberately does not perform.

The alg: none attack. RFC 7519 allows an "unsecured" JWT whose header says "alg": "none" and which carries no signature. Several libraries historically accepted these by default, letting an attacker forge any payload they liked. The defence is to pin the expected algorithm when verifying and reject none outright. Because this tool only decodes, an alg: none token displays without complaint — a useful reminder of why blind trust is dangerous.

Times are seconds, not milliseconds. exp, iat, and nbf are Unix timestamps in seconds (per the spec's NumericDate). A frequent bug is passing Date.now() — which is milliseconds — straight into exp, producing a token that "expires" tens of thousands of years from now. If your token never seems to expire, check the magnitude of exp; a 13-digit value is milliseconds and wrong. A dedicated Unix timestamp converter (coming soon) makes checking these against a wall-clock date quick.

Claims worth knowing. Beyond timing, watch for iss (issuer), aud (audience), and sub (subject). A verifier should check that aud matches your service and iss matches the expected identity provider — a valid signature on a token minted for a different audience is still not a token for you.

The payload is ordinary JSON, so you can pretty-print it with the JSON formatter; the whole token is Base64URL under the hood.

Examples

Decode a standard HS256 token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

The canonical example token — header, payload with sub/name/iat, and a signature.

Spot an expired token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsIm5hbWUiOiJHcmFjZSBIb3BwZXIiLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE1MTYyMzkwMjIsImV4cCI6MTYwMDAwMDAwMH0.c2lnbmF0dXJl

This payload has an exp in the past, so the claims panel flags it as expired.

Frequently asked questions

Is it safe to paste a JWT here?

This decoder runs entirely in your browser and never transmits the token. That said, treat production tokens as credentials — decoding one on any tool reveals its claims, and this one simply does so locally.

Does decoding a JWT verify it?

No. Decoding only Base64URL-decodes the header and payload; it proves nothing about authenticity. A tampered token, or one using the "alg: none" trick, still decodes cleanly. Verification requires the signing secret or public key.

Why does my token show as expired?

The "exp" claim is a Unix timestamp in seconds (not milliseconds). If the current time is at or past that instant, the token is expired. A common bug is storing exp in milliseconds, which pushes expiry to the year 52,000.

What is the "alg: none" attack?

Some libraries once accepted tokens whose header said "alg": "none", meaning unsigned, and skipped verification. An attacker could forge any payload. Always pin the expected algorithm when verifying, and never trust the header’s alg blindly.

What are iat, nbf and exp?

iat is when the token was issued, nbf ("not before") is the earliest it is valid, and exp is when it expires — all Unix seconds. This tool shows each as a human-readable UTC date so you can sanity-check them.