JWT decoder
MDV ToolsPaste a token. Read its header, payload and claims, with the times as dates. The signature is not verified — this page decodes, it does not check; checking needs the key. The token never leaves this page.
How this works
A JWT is three base64url strings joined by dots: header, payload, signature. The first two
are decoded by swapping - and _ back to + and
/, adding the = padding the token format leaves off, running
atob, and reading the bytes as UTF-8 with TextDecoder in fatal mode,
so a byte sequence that is not UTF-8 is reported rather than guessed. Each result goes through
JSON.parse and is printed back with JSON.stringify(value, null, 2);
when parsing fails, the parser's own message and position are passed on, and the decoded text is
shown under the error — up to 300 characters either side of that position, with the character
there marked. A message about the input ending early marks the end of the text; any other
message that names no position gets the first 600 characters, unmarked. Whitespace and line
breaks anywhere in the pasted text are ignored and a leading Bearer is dropped,
so a token copied out of an HTTP header decodes as it is.
The signature is not verified. Verifying needs the issuer's key — the HMAC secret or the
public key — and this page has neither and asks for neither; it reports only how many bytes
the signature holds, and says when the signature part is empty and when alg is
none — including when such a token still carries signature
bytes, which RFC 7518 forbids. Times are the iat, nbf and
exp claims read as seconds since 1970-01-01 UTC, printed with
Date.prototype.toISOString, and compared with Date.now() at the moment
of decoding. RFC 7519 times are seconds, so a value above 100,000,000,000 — past the year 5000 —
is flagged as not in seconds, shown as it would read in milliseconds, and never judged: the
badge says "not in seconds" instead of Expired, Not yet expired or Not yet valid. An
nbf still in the future shows Not yet valid, ahead of any
exp verdict, or Never valid when exp is not after it. The relative
text does not tick, and the badge trusts this device's clock, not the issuer's.
Input above 100,000 characters is refused rather than attempted. The token is held in the
text box and nowhere else: there is no server in this file, nothing is written to storage,
and closing the tab discards it. Claims are shown as the token states them — aud
may be a string or a list and is printed either way; a claim that is missing shows as a dash.
The Dark button remembers its setting in this browser's local storage. Nothing you type or drop into the page is stored.