JWT · JSON Web Token

JWT Decoder.

Paste any JSON Web Token to see its header, claims, and signature decoded inline. We highlight expiration, "not before", and the algorithm — everything runs in your browser.

JWT Decoder
Important

Decoding only reveals what is inside the token. It does not verify the signature, check expiration, or confirm the issuer. Never trust a decoded JWT as proof of authentication — use a vetted JWT library for signature verification.

Frequently asked

About this tool.

A JWT is a compact, URL-safe token used for stateless authentication and information exchange. It has three parts: a header describing the algorithm, a payload containing claims (like user ID and expiration), and a signature for tamper detection. Each part is Base64URL-encoded and joined with dots.

No. Decoding only reveals what is inside the token — the header and claims are readable by anyone. Verifying a JWT requires the signing key (a secret for HMAC, a public key for RSA or ECDSA) and confirms that the token has not been tampered with. Our tool only decodes; it does not verify. Never trust the contents of a JWT as proof of authentication without verifying the signature.

No, this tool only handles signed JWTs (JWS). Encrypted JWTs (JWE) require the decryption key. If your token has five segments separated by dots instead of three, it is a JWE and cannot be decoded without the key.

It means the token is unsigned. Historically this was a major security vulnerability — attackers could forge tokens by setting alg to "none". Reputable libraries reject unsigned tokens by default. Our decoder displays a warning when it encounters one.

No. Decoding happens entirely in your browser using JavaScript. Nothing is uploaded, stored, or logged. You can verify this with your browser DevTools — the Network tab stays silent during decode.

A JWT is three Base64URL segments joined by dots (header.payload.signature). The header names the token type and signing algorithm (e.g. HS256, RS256). The payload holds the claims — user ID, roles, expiry. The signature is a hash of the encoded header and payload combined with a secret or private key, and it is what proves the token has not been altered.
A JWT is signed, not encrypted. The payload is just Base64URL text, so anyone holding the token can decode and read it instantly — paste one into this decoder and you will see every claim in plain text. Never place passwords, API keys or personal data in a payload; keep it to non-sensitive identifiers and authorization claims.
The server recomputes the signature: it takes the received header and payload, hashes them with the algorithm named in the header plus its own secret (HS256) or public key (RS256), and compares the result to the signature on the token. If they match, the payload is authentic and untampered. This check must always happen server-side.
The exp claim is just data in a readable payload — a user can edit their local clock or a client-side check to ignore it. Only the server, validating the signature and comparing exp against its own trusted time, can actually enforce expiry. Client-side expiry checks are a UX convenience, not a security control.
HS256 is symmetric: one shared secret both signs and verifies, so any party that can verify can also mint tokens. RS256 is asymmetric: the issuer signs with a private key and anyone can verify with the matching public key, without the power to forge tokens. Use RS256 when tokens are verified by services you don't fully trust to hold a signing secret.
localStorage is readable by any JavaScript on your origin, so a single XSS flaw lets an attacker read the token and hijack the session. A HttpOnly, Secure cookie is safer because scripts can't read it. If you must use localStorage, keep token lifetimes short and treat XSS prevention as critical.
An empty signature means the token uses the alg: none configuration. It is occasionally used in testing, but production servers must reject unsigned tokens — accepting one enables a signature-bypass attack where anyone can forge claims.
Split on the dots and Base64-decode the middle segment — no library is needed to read (not verify) the claims:
const payload = token.split('.')[1];
const claims = JSON.parse(Buffer.from(payload, 'base64').toString('utf-8'));
Decoding only reads the token; always verify the signature server-side before trusting it.
Related tools

More from the toolkit.