Skip to content

JWT Decoder

Decode a JWT's header and payload, check expiry, and verify HS256/384/512 signatures — entirely client-side, and decoding is never confused with verifying.

Encoded token

Verify signature

Paste a token to check its signature.

The secret stays in this tab. It is used only by your browser's WebCrypto implementation and is never transmitted.

Header

Decoded header appears here.

Payload

Decoded payload appears here.

About the JWT Decoder

A JSON Web Token is three base64url-encoded segments joined by dots: a header describing the signing algorithm, a payload of claims, and a signature over the first two. Decoding the first two segments requires no key at all — which is exactly why you should never put a secret in a JWT payload.

This decoder splits the token, decodes the header and payload, and interprets the registered claims: it shows when the token expires, whether that moment has already passed, and what iat and nbf work out to in real time. If the token is signed with HS256, HS384 or HS512 you can paste the shared secret and verify the signature using your browser's WebCrypto implementation.

Nothing leaves the page. The token and the secret are held in the tab's memory only — no request is made, so it is safe to inspect a production access token.

Decoding and verifying are different operations, and this tool is careful to keep that distinction visible rather than blur it. Decoding just base64url-decodes the first two segments — anyone can do it, with or without the secret, because the payload was never encrypted in the first place. Verifying checks the third segment, the signature, against a key, and is the only step that says whether the token can be trusted. A token can decode perfectly and still be a forgery; jwt.io and every other decoder share this same distinction, because it is a property of the JWT format itself, not a limitation of any particular tool.

  • Colour-coded header, payload and signature segments
  • HS256, HS384 and HS512 signature verification via WebCrypto, with plain or base64-encoded secrets
  • Expiry, not-before and issued-at claims rendered as absolute UTC time plus a relative description
  • Registered claim names annotated with their meaning from RFC 7519
  • A leading "Bearer " prefix stripped automatically, so a header copied straight from a request works unedited

How to use it

  1. Paste the token into the encoded pane. A leading "Bearer " is stripped automatically.
  2. Read the decoded header to see which algorithm signed it, and the payload for the claims.
  3. Check the exp row — a red value means the token has already expired.
  4. To verify the signature, paste the shared secret. Tick "Secret is base64-encoded" if your issuer stores it that way, as Auth0 historically did.
  5. Copy the decoded header or payload as formatted JSON.

Real-world use cases

Backend & API developers

Decode an access token during local development to confirm the claims your middleware is actually reading, instead of adding a temporary console.log to check what the auth library parsed.

Frontend developers

Check why a token stored after login looks expired or malformed, reading exp and iat directly rather than guessing from a vague 401 in the network tab.

QA & support engineers

Paste a token from a bug report to see its expiry and claims immediately, without needing the signing secret or access to the issuing service.

DevOps & platform engineers

Verify that a token minted by a new auth service configuration carries the expected issuer, audience and expiry before wiring it into a downstream API gateway.

Security & AppSec engineers

Confirm a token's algorithm and claims during an audit or an incident, and verify HS256/384/512 signatures locally without sending a live production token to a third-party server.

Examples

A minimal HS256 token

Input
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjIwMDAwMDAwMDB9.…
Output
header  { "alg": "HS256", "typ": "JWT" }
payload { "sub": "123", "exp": 2000000000 }
exp     2033-05-18T03:33:20Z (in 7 years)

An expired token

Input
{ "sub": "123", "exp": 1600000000 }
Output
exp  2020-09-13T12:26:40Z (6 years ago) — expired

Servers reject this with a 401. The signature can still be perfectly valid — expiry and authenticity are separate checks.

Common errors

MessageCauseFix
Invalid token specifiedThe string has fewer or more than three dot-separated parts, often because the "Bearer " prefix or a trailing newline was copied along with it.Copy only the token. Five parts means it is a JWE (encrypted), which cannot be decoded without the key.
invalid signatureThe secret does not match, or the token was signed with a different algorithm than the verifier expects.Confirm the secret and check the alg in the header. A base64-encoded secret must be decoded before use.
jwt expiredThe exp claim is in the past, or the server's clock has drifted ahead of the issuer's.Refresh the token. If exp looks correct, check for clock skew between the two machines.
jwt not activeThe nbf claim is in the future.Wait until nbf, or correct the clock on the issuing machine.
alg: noneAn unsigned token. Historically a real attack: some libraries accepted it as valid.Reject these outright and pin the expected algorithm in your verification call.

Frequently asked questions

Is the token or secret sent anywhere?

No. Decoding and verification run in your browser — the signature check uses the WebCrypto API built into the browser itself. No network request is made, so production tokens are safe to paste.

Can anyone read a JWT payload?

Yes. The payload is base64url-encoded, not encrypted, so anyone holding the token can read every claim in it. Never store passwords, keys or personal data you would not want exposed. If the contents must be secret, use an encrypted JWE instead.

What does it mean when a signature is valid but the token is expired?

They are independent checks. A valid signature proves the token was issued by whoever holds the secret and has not been altered. The exp claim states how long that issuer intended it to be accepted. A tampered token fails the first check; an old token fails the second.

Why can I not verify an RS256 token?

RS256, ES256 and PS256 are asymmetric: verification requires the issuer's public key, usually published at a JWKS endpoint. This tool accepts shared secrets only, so it verifies the HS family. Decoding still works for every algorithm.

Should the secret be treated as plain text or base64?

It depends on the issuer. Most libraries treat the secret as raw UTF-8 bytes. Some platforms store it base64-encoded, in which case it must be decoded first — verifying with the wrong interpretation produces a signature mismatch even when the secret is correct.

What is the difference between a JWT and a JWE?

A JWT in its common JWS form has three segments and is signed but readable. A JWE has five segments and is encrypted — the payload cannot be decoded without the decryption key.

Is decoding a JWT the same as verifying it?

No, and this is the single most common misunderstanding about JWTs. Decoding reads the header and payload — no key required, because they were never encrypted. Verifying checks the signature against a key and is what actually proves the token was issued by whoever holds the secret and has not been tampered with. This tool decodes every token you paste, and separately verifies the signature only when you supply the matching secret.

Why does the payload show fields I did not expect?

Some claims are added automatically by the library or service that issued the token, not chosen by whoever wrote the application code — iat (issued at) is set to the signing time, and jti or a session identifier are often injected by an auth platform's SDK. If a claim looks unfamiliar, check the issuer's documentation before assuming it was added by mistake.

Last updated