JWT Decoder

Read a JSON Web Token: its header, its claims exactly as written, its signature and its times, with a warning for anything a server would refuse. Nothing is verified and nothing leaves the browser.

Overview

A JSON Web Token (JWT, RFC 7519) carries claims, such as who a user is and until when the token is valid, from one party to another. A signed token (JWS, RFC 7515) has three parts separated by dots: a header that names the algorithm, the payload with the claims, and a signature over both. Header and payload are JSON written in Base64url, so anyone holding the token can read them. The signature only shows that nobody changed them.

An encrypted token (JWE, RFC 7516) has five parts. Its header is readable too, but its payload can only be read with the recipient's key.

Web interface

Paste a token into the input; header and payload appear as you type. The hints give the algorithm, type and key id of the header and the number of claims, and the line under the output describes the signature, the times and any warnings. Copy Header and Copy Payload copy the JSON, Clear empties everything, Ctrl/ + Enter decodes again.

The dice in the corner of the input loads a random example, a different one each time; see Examples.

What the input may be

Tokens rarely arrive clean. The input accepts them as they are copied:

  • behind Bearer or a whole Authorization: Bearer header line;
  • in double or single quotes, as in JSON or a configuration file;
  • wrapped over several lines: all spaces and line breaks are removed.

The hint above the input says what was removed. A token in the standard Base64 alphabet, with + and / instead of - and _, is read with a warning, and = padding at the end is accepted.

Header and payload

Header and payload are shown as JSON exactly as they stand in the token, only indented. The numbers are not converted, so 12345678901234567890 keeps every digit, where a JavaScript number would turn it into 12345678901234567000. Escapes and keys that appear twice stay as they are too.

A payload that is not JSON is shown as text: that is a signed message (JWS), but not a JWT. A payload that is JSON but not an object, such as null or a list, is shown with a warning, since JWT claims have to be an object.

Times and warnings

The three time claims are shown in UTC, with how long ago or how far ahead they are:

ClaimShown asWarning when
iat, issued atIssued 2026-09-12 14:03:00 UTC, 2 hours ago.it lies in the future
nbf, not beforeValid from 2026-09-12 14:03:00 UTC.it lies in the future: the token is not valid yet
exp, expiresExpires 2026-10-12 14:03:00 UTC, in 29 days.it has passed: the token is expired

JWT times are seconds since 1970. A time that is not a number is reported, and so is a number above 100 billion, which as seconds would lie beyond the year 5000 and is almost always milliseconds. A token without exp is noted as having no expiry time. The payload hint adds expired, not valid yet or unsigned to the number of claims.

Signatures

The signature is not verified. For an HMAC token (HS256, HS384, HS512) that would take the shared secret, for an RSA, ECDSA or EdDSA token the issuer's public key. The line under the output names the algorithm and the size of the signature, and warns when:

  • the header says "alg": "none": the token is unsigned, and anyone can change it;
  • the header names no algorithm;
  • the signature is empty although the header names an algorithm;
  • the size does not fit the algorithm. HMAC and ECDSA signatures have a fixed size: 32, 48 and 64 bytes for HS256, HS384, HS512, and 64, 96 and 132 bytes for ES256, ES384, ES512.

Examples

The dice builds a new example on each click, so its times are relative to the moment you roll:

ExampleWhat it shows
valid for an houran ordinary HS256 token
expiredexp one day ago, with issuer and audience
not valid yetnbf one day ahead
HS512 with key id and two audiencesa kid in the header and aud as a list
ES256 without typan ECDSA token whose header names no type
unsigned (alg: none)a token without a signature
a number too large for JavaScript12345678901234567890, kept digit for digit
encrypted (JWE)a token with five parts whose payload cannot be read

The HMAC examples are signed with the secret troubleshooting.tools sample secret, so they can be verified elsewhere. The ES256 example is signed and the JWE example encrypted with a key that is made on the spot and thrown away: nobody can verify or read them, which for the JWE is the point.

Errors

A token that cannot be read is not shown half-way. The output stays empty and the line under it says why:

MessageMeaning
a JWT has three parts separated by dots, five when it is encrypted; this has 2Part of the token is missing, or it is no JWT.
the header contains “*”, which is not a Base64url characterA character that has no place in a token, named in the message.
the header is one character too long or too short for Base64urlThe token was cut off or a character was lost when copying.
the header is not JSON, the header has to be a JSON objectThe first part decodes, but not to a header.
the payload is not valid UTF-8 textThe part decodes to bytes that are no text.

No API

There is no API for this tool, and there should not be one: a token is a credential, and pasting it into a service is handing it over. Decoding runs in the browser; in a program, use a JWT library of the language at hand, which can also verify the signature.

Limits

The input has no length limit. The examples are signed and encrypted with the browser's own cryptography (Web Crypto), which browsers only offer on HTTPS pages; where it is missing, the dice is hidden and pasted tokens are decoded all the same.

Privacy

Nothing leaves the browser. The token is decoded on the page, nothing is stored, and Copy writes to the clipboard only when you press it. Still, treat a real token like a password: anyone who has it can use it until it expires.