JWT Decoder

Decode a JSON Web Token to read its header and payload claims — no secret needed.

JWT Decoder Online: Decode a JSON Web Token's Header, Payload and Claims

Paste a JSON Web Token into the box above. The decoder splits it at the dots, decodes the header and payload from Base64url and shows both as formatted JSON. The time claims `exp`, `iat` and `nbf` are converted to readable UTC dates, and the decoder tells you whether the token has expired. The token is decoded in your browser and never sent to a server, which matters because a JWT is often a live credential.

What you see after decoding

A JWT has three parts separated by dots: header, payload and signature. The first two are Base64url-encoded JSON; the third is the signature bytes.

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMjQtMTAifQ      header
.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzEy…  payload
.<signature>

header:  { "alg": "RS256", "typ": "JWT", "kid": "2024-10" }
payload: { "iss": "https://auth.example.com", "sub": "user_123", "aud": "api",
           "exp": 1790003600, "iat": 1790000000, "scope": "read:orders" }

exp: 2026-09-21T15:13:20.000Z
iat: 2026-09-21T14:13:20.000Z

The header names the signing algorithm (alg) and often a key ID (kid) that tells the server which public key to use. The payload holds the claims: who issued the token, who it is about, who it is for, when it expires, and any application data such as scopes or roles.

Below the payload, the decoder lists exp, nbf and iat as ISO dates in UTC, marks exp as (EXPIRED) or (not expired) against your computer's clock, and flags an nbf in the future as (not yet valid). If your laptop's clock is off, so is that label.

Registered claims

RFC 7519 defines seven registered claim names. None is mandatory, but most identity providers use all of them:

iss   issuer       who created and signed the token (your identity provider)
sub   subject      the user or client the token is about
aud   audience     the API or app the token is intended for
exp   expiration   Unix time in seconds after which the token must be rejected
nbf   not before   Unix time before which the token must be rejected
iat   issued at    Unix time the token was created
jti   JWT ID       unique identifier, used to detect replay or revoke a token

Times are NumericDate values: seconds since 1970, not milliseconds. A token whose exp seems to be in 1970 or tens of thousands of years in the future was built with the wrong unit. OpenID Connect ID tokens add claims such as email, name and nonce; Auth0, Okta, Azure AD and Keycloak add their own, often namespaced ones.

Decoding is not verifying

Anyone can decode a JWT. The header and payload are only encoded, not encrypted, so the decoder needs no key and a decoded payload proves nothing about who made it. An attacker can change "role": "user" to "role": "admin", re-encode it and the token decodes perfectly; only the signature check exposes the change.

Use the decoder to read tokens while debugging. Before trusting any claim in an application, verify the signature with the secret or public key and check exp, nbf, iss and aud, using a maintained library such as jose, jsonwebtoken, PyJWT or firebase/php-jwt. To check a signature by hand, paste the token and key into the JWT validator.

If you are used to the jwt.io debugger, note the split here: this page only decodes, and the validator checks the signature against a secret or public key.

Decoding a JWT in code

Decoding is a few lines in any language, which is useful for logging or for reading exp on the client to refresh a token before it expires:

// JavaScript (browser or Node.js 16+)
const [header, payload] = token.split('.').slice(0, 2)
  .map((part) => JSON.parse(new TextDecoder().decode(
    Uint8Array.from(atob(part.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0)))));

# Python, PyJWT: read without verifying (debugging only)
jwt.decode(token, options={"verify_signature": False})

# Shell
echo "$TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null

The shell version may complain or drop the last few characters, because JWTs omit the = padding that base64 -d expects; append = until the length is a multiple of four for a clean result. The TextDecoder step in JavaScript matters: atob alone garbles non-ASCII names and emails in the payload.

When decoding fails

A JWT has exactly three dot-separated parts. Two parts usually means the token was cut when copying; five parts means it is a JWE, an encrypted token whose payload cannot be read without the decryption key. A leading Bearer from an Authorization header is not part of the token, so remove it before pasting.

If the payload decodes to unreadable bytes, the token may be encrypted or compressed, or it may not be a JWT at all: opaque access tokens from some providers are random strings that only the issuing server can look up. Tokens that start with eyJ are JSON, because eyJ is the Base64 encoding of {".

Keep tokens private

A valid access or ID token lets whoever holds it act as the user until it expires. Keep production tokens out of tickets and chat, and out of online tools that post what you paste to a server. If you need to share one for debugging, delete the third part first: the claims stay readable and the token stops working.

JWT payloads are readable by anyone who holds the token, including the browser and every proxy that logs headers. Do not put passwords, API keys or sensitive personal data in claims.

Frequently asked questions

How do I decode a JWT?

Paste the token into the decoder. The header and payload are shown as JSON, and exp, iat and nbf are converted to readable dates with the expiry status.

Can I decode a JWT without the secret?

Yes. Reading a JWT needs no key at all, because only the signature is protected. Without the secret or public key you can see every claim, but you cannot tell whether anyone edited them.

Does decoding a JWT verify it?

No. Decoding only reads the contents. A modified token decodes just as well, so verify the signature and the exp, iss and aud claims before trusting it.

How do I check if a JWT has expired?

Look at the exp claim, a Unix time in seconds. The decoder converts it to a date and shows whether it is already in the past.

Why does my token have five parts?

It is a JWE, an encrypted JWT. Its contents cannot be decoded without the decryption key.

Is it safe to paste my token here?

The token is decoded in your browser and never sent anywhere. Still, treat live tokens as passwords and avoid sharing them.