Tool

JWT decoder and expiry checker

Paste a JWT to decode its header and payload in your browser — exp, nbf and iat shown in UTC, Beijing time and your local timezone with a live countdown. Decode only, signature never verified.

Token input

Processing: decoding runs entirely in this browser tab — the token is never sent, stored or written into links. Closing the tab discards it.

Decode only — the signature is NOT verified. A parseable token is not proof of authenticity; never trust its contents for access decisions.

How decoding works

Three segments. A compact JWT is header.payload.signature — three base64url-encoded segments split by dots. Anything that is not exactly three segments is rejected with a segment-count error. A leading Bearer scheme (any case) followed by whitespace, plus leading/trailing whitespace, is stripped before splitting.

base64url + UTF-8. Each segment is decoded with the URL-safe alphabet (- and _ instead of + and /); missing = padding is restored automatically, while a length of mod-4 = 1 or any non-base64url character reports a decode failure. Bytes are interpreted as UTF-8, so CJK names and emoji survive intact. The signature segment may be empty (unsigned alg:"none"-style tokens) but is still validated as base64url. It is never used to verify anything.

Time claims are seconds. exp (expires at), nbf (not valid before) and iat (issued at) are NumericDate values — seconds since 1970-01-01 UTC. They render side by side in UTC, Beijing time (fixed UTC+8) and your browser's local timezone. A numeric string like "1735689600" is accepted and flagged as string-typed; booleans, null, objects, arrays and non-numeric strings are hard errors. The countdown ticks every second: it shows time-until-expiry, time-since-expiry, or time-until-activation when nbf is in the future, plus how long ago iat was issued.

Parseable ≠ verified. This tool only decodes — it never validates the signature or the issuer. The two badges say exactly what is known: the token is parseable (structure) and its signature is not verified. The time badge only reports exp/nbf arithmetic — "not expired" never means the token is trustworthy. Everything runs in this tab: nothing is sent, stored, written into links or kept in localStorage. Related tools: JSON structural diff, log redaction, JSON ↔ CSV converter.

FAQ

Is my token uploaded or stored anywhere?

No. Decoding runs entirely inside this browser tab — the token is never sent to a server, written to disk, embedded in a link, or stored in localStorage. Closing the tab discards it.

Why doesn't this tool verify the signature?

Verification needs the issuer's secret or public key, and pasting those into a web page is a bigger risk than decoding. This tool deliberately only decodes: the badges always show 'parseable' and 'signature not verified' — a readable payload proves nothing about authenticity, and 'not expired' never means the token is trustworthy.

What unit are exp, nbf and iat in?

NumericDate — seconds since 1970-01-01 UTC (not milliseconds). exp is the expiry instant, nbf is the not-valid-before instant and iat is when the token was issued. Each claim is shown in UTC, Beijing time (fixed UTC+8) and your browser's local timezone; a numeric string like "1735689600" is accepted and flagged, while booleans, null, objects and arrays are errors.

What does 'not yet active' mean?

The nbf (not before) claim is in the future, so the token should not be accepted yet — the countdown shows the time remaining until it takes effect. An exp in the past shows 'expired', a missing exp shows 'no expiry claim'.

My token pasted from an Authorization header fails — why?

It should not: a leading 'Bearer ' scheme (any letter case) plus whitespace is stripped automatically, as is surrounding whitespace. What still fails: fewer or more than three dot-separated segments, non-base64url characters, a segment length of mod 4 = 1, segments that decode to invalid JSON, and non-numeric time claims — each gets its own specific error message.