Encoding tool

JWT Decoder

Decode a JWT in your browser: header, payload and exp, iat and nbf as dates with an Expired badge. The signature is not verified and nothing is uploaded.

Last updated

A JSON Web Token, or JWT (said "jot"), is how many sites and APIs keep you signed in. After you log in the server hands your browser a token, and the browser sends it back with each request to say who you are. A JWT decoder reads the token for you: it shows the claims inside, such as who the token is for and when it runs out.

303 characters

Not verified. This decodes the token and reads what it says. It does not check the signature, so it cannot tell you the token is genuine. The token stays in your browser: nothing is sent to a server, and it is not sent to our analytics either.

Header (HS256)

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

{
  "sub": "1234567890",
  "name": "Coding Kitty",
  "iss": "https://thecodingkitty.com",
  "aud": "kitty-app",
  "iat": 1767225600,
  "nbf": 1767225600,
  "exp": 1767229200,
  "scope": "read:cats"
}

Claims

  • subSubject

    1234567890

  • nameName

    Coding Kitty

  • issIssuer

    https://thecodingkitty.com

  • audAudience

    kitty-app

  • iatIssued at

    1767225600

    2026-01-01 00:00:00 UTC

  • nbfNot before

    1767225600

    2026-01-01 00:00:00 UTC

  • expExpiration time

    1767229200

    2026-01-01 01:00:00 UTC

  • scopeScope

    read:cats

Signature (not verified)

J_-9cZLT1xmkp9oNqc3Z17NmiEuyE0AF1cr-WC0VbOk

32 bytes. Checking it needs the secret or public key, which stay with whoever issued the token.

Runs in your browser. Nothing you paste is uploaded.

Paste a token and it decodes as you type. The header and payload are shown as formatted JSON, every claim is listed with its meaning, and exp, iat and nbf are shown as dates in UTC and in your own time zone. The token above is a sample signed with a throwaway secret.

What is inside a JWT

A JWT is three parts separated by dots, each written in base64url:

PartWhat it holdsReadable here
HeaderThe signing algorithm (alg) and the token type (typ)Yes, as JSON
PayloadThe claims: who the token is about, who issued it, when it expiresYes, as JSON
SignatureA signature over the first two parts, made with a secret or private keyShown, not checked

The first two parts are not secret. Base64url is a way of writing bytes as safe text, the same idea as Base64 with - and _ in place of + and /, and no = padding. Anyone holding the token can read them, which is why a payload should never carry a password.

The claims you will see

ClaimNameWhat it means
issIssuerWho created and signed the token
subSubjectWho the token is about, usually a user ID
audAudienceWho the token is for. A service should refuse a token not meant for it
expExpiration timeThe token must not be accepted at or after this moment
nbfNot beforeThe token must not be accepted before this moment
iatIssued atWhen the token was created
jtiJWT IDA unique ID for this token, so it can be revoked or seen only once

Anything else is a custom claim, such as scope, email or a roles list. Names the decoder knows get a label, and the rest are shown as they are.

How to check whether a JWT has expired

Look at exp. It is a number of seconds since 1 January 1970 UTC, so 1767229200 is 1 January 2026 at 01:00 UTC. If the time now is at or after that, the token has expired and a server should reject it. The decoder does the comparison against your clock and badges the exp row Expired or Not expired. If nbf is in the future the row says Not yet valid, because the token is not usable yet.

Two things to know when a token that looks fine is rejected. First, servers allow a little clock skew, often a minute or so, so a token a few seconds past its exp may still be accepted by one server and refused by another. Second, your own clock matters here: a wrong clock on your computer shows the wrong badge.

Decoding is not verifying

Decoding reads the token. Verifying checks the signature, with the secret or public key, to prove the header and payload were not changed since the issuer signed them. This page decodes and does not verify, and it cannot, because it never has the key.

  • A token that decodes can still be forged. Anyone can write a header and a payload and make them look right. Only the signature check proves who issued it.
  • alg: none is a warning. A token with no signature is accepted by a badly configured server as genuine. The decoder flags it.
  • Decode in the browser, verify on the server. Never decide who a user is from a decoded token in client code. Do that with a library on the server that checks the signature, the exp, the iss and the aud.

Gotchas

  • Expiry is in seconds. JavaScript's Date.now() is in milliseconds, so compare exp with Date.now() / 1000.
  • A JWT is not encrypted. A signed token is readable by anyone who sees it. Treat a live one like a password, and prefer expired or test tokens when you paste one anywhere.
  • Five parts means encrypted. A JWE has five dot-separated parts and cannot be decoded without its key.
  • A Bearer prefix is fine. Copied from an Authorization header, it is stripped for you, as are quotes and line breaks.
  • Opaque tokens are not JWTs. Some services issue a random string with no dots. There is nothing to decode in one, because the meaning lives on the server.

Common questions

How do I decode a JWT?

Paste the token into the box above. It is split at the two dots into a header, a payload and a signature. The header and payload are base64url text that holds JSON, so the decoder reads them back and shows them formatted, with the exp, iat and nbf claims as dates. The signature is binary and is shown as it is.

Is this JWT token decoder online safe to paste a token into?

The decoding runs in your browser and the token is not sent to a server or to our analytics. We record that the tool was used and how long the paste was, never what it said. Even so, treat a live token like a password: it lets whoever holds it act as you until it expires, so prefer a test token or one that has already expired.

Does the decoder verify the signature?

No, and it cannot. Checking a signature needs the secret key (for HS256) or the public key (for RS256 and ES256), and that stays with the service that issued the token. The decoder only reads what the token says about itself, so a forged token decodes just as well as a real one. Never trust a token because it decodes.

Is a JWT encrypted?

Usually not. A normal signed JWT (a JWS) is only encoded: anyone who has it can read the header and payload, which is exactly what this JWT parser does. Do not put secrets in a payload. An encrypted JWT (a JWE) has five parts instead of three and cannot be read without the key, and this decoder says so when it sees one.

How do I tell whether a JWT has expired?

Read the exp claim. It is a time in seconds since 1 January 1970 UTC, and a token is not to be accepted at or after that moment. The decoder shows exp as a date, compares it with your clock, and puts an Expired or Not expired badge on it. A token whose nbf (not before) is still in the future is marked Not yet valid.

What do iss, sub, aud, exp, nbf, iat and jti mean?

They are the registered claims. iss is the issuer that created the token, sub the subject it is about (usually a user ID), aud the audience it is meant for, exp when it expires, nbf the time before which it is not valid, iat when it was issued and jti a unique ID for the token. The decoder labels each one it finds in the Claims list.

Why does my JWT say it is not valid base64url?

Each part of a JWT uses the URL-safe alphabet: A to Z, a to z, 0 to 9, a hyphen and an underscore, with no equals padding. A plus, a slash or an equals sign means the part was made with ordinary Base64, and any other character usually means the token was cut, quoted or had extra text pasted in. The error names the character and where it is.

Why does it say my token has the wrong number of parts?

A signed JWT is exactly three parts joined by two dots. Two parts usually means the signature was cut off, and one means this is not a JWT at all, perhaps an opaque access token or an API key. Five parts is an encrypted JWT. A leading Bearer prefix or surrounding quotes are removed for you, but anything else glued to the token will break it.

Why are the dates in seconds and not milliseconds?

The JWT standard defines exp, nbf and iat as a count of seconds, not the milliseconds JavaScript uses for Date.now(). A value like 1767229200 is a normal date in 2026, while the same number with three more digits would be far in the future. If a decoded date looks like the year 55000, the token was probably issued with milliseconds by mistake.

See all tools

Want this explained by a cat?

The videos cover the same ground in sixty seconds. If there is a tool you want built next, ask.