How to read a JWT, and why decoding is not verifying

Anyone holding a JSON Web Token can read what is inside it. That is by design, and it is why you should not trust a token just because you were able to decode it. How a JWT is built, how to read one in a minute, and what has to happen before you believe its contents.

Reviewed on 3 October 2026 · 4 min read

The three parts

A JWT is a string of three base64url-encoded parts separated by dots: header.payload.signature. RFC 7519 describes it as a sequence of URL-safe parts separated by period characters, each containing a base64url-encoded value. Here is a small made-up example (signed with a throwaway key; it grants nothing):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFuYSIsImlhdCI6MTcwMDAwMDAwMCwiZXhwIjoxNzAwMDAzNjAwfQ.gXp1Px7z_ClrGj78UjJKhSZ71IuYJpyz5YWbOqOSVQo
  • Header (eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9): decodes to {"alg":"HS256","typ":"JWT"}, which says the token is signed with HMAC SHA-256.
  • Payload (the middle part): decodes to {"sub":"1234567890","name":"Ana","iat":1700000000,"exp":1700003600}. These are the "claims".
  • Signature (the last part): a cryptographic value computed over the first two parts with a secret or private key. It is binary data, so decoding it gives nothing readable.

How to decode one in a minute

Paste the token into the JWT decoder. It splits the token, decodes the header and payload and shows them as formatted JSON, and it does so in your browser: a token often carries a user's identity, so it is best not to paste a real one into a site that sends it to a server. If you prefer to do it by hand, take the first and second parts and run each through a base64url decode (swap - for + and _ for /, add = padding until the length is a multiple of 4, then decode as base64); the Base64 tool does that step.

The claims you will see most

RFC 7519 registers a few standard claim names. The ones you will meet constantly:

ClaimMeaning
ississuer: who created the token
subsubject: who the token is about (often a user ID)
audaudience: who the token is meant for
expexpiration time: from this moment the token must not be accepted
nbfnot before: the token must not be accepted before this time
iatissued at: when it was created
jtiJWT ID: a unique identifier for the token

The time claims (exp, nbf, iat) are a NumericDate: the number of seconds since 1970-01-01T00:00:00Z UTC, ignoring leap seconds, the same Unix time that POSIX defines. In the example, iat is 1700000000 (14 November 2023, 22:13:20 UTC) and exp is 1700003600, exactly one hour later. The timestamp converter turns those numbers into dates; if you mix seconds and milliseconds, see the guide to Unix timestamps. RFC 7519 also says exp is checked by comparing it with the current time, and that implementers may allow a small leeway, usually no more than a few minutes, for clock skew.

Decoding is not verifying

This is the mistake that causes real vulnerabilities. Anything in a JWT payload can be read by anyone who has the token, because base64url is an encoding, not encryption, and anyone could also write a payload that says whatever they like. What stops forgery is the signature, and the signature only helps if the server actually checks it.

Verifying means recomputing the signature with the right key and comparing it, and then checking the claims: that exp has not passed, that aud is you, that iss is who you expect. A tool that decodes a token (including ours) tells you what the token claims; it does not tell you whether it is genuine. Do not make access decisions on a payload you have only decoded.

RFC 8725, the best-current-practice document for JWTs, documents what goes wrong when this is skipped. It describes how an attacker can change the algorithm to none and some libraries would "validate" the token without checking any signature, and how an RS256 token can be switched to HS256 so that a library uses the RSA public key as the HMAC secret. Its mitigations include letting the caller choose the supported algorithms, never accepting others, and using each key with exactly one algorithm. It also warns that applications should not trust received claims without validating them, including issuer, subject and audience.

Do not put secrets in the payload

Because the payload of a signed token is readable, do not store passwords, card numbers or other secrets in it. RFC 7519 says that a JWT may contain privacy-sensitive information and that measures must be taken to prevent its disclosure: use an encrypted JWT, or make sure tokens with unencrypted sensitive information only travel over TLS, and, simplest of all, leave the privacy-sensitive information out. Remember too that a token tends to end up in logs, browser storage and URLs.

Practical checks when a token "does not work"

  1. Expired? Convert exp to a date and compare it with now. Clock skew between servers is a frequent culprit.
  2. Wrong audience or issuer? Compare aud and iss with what your service expects.
  3. Wrong algorithm or key? Check alg in the header against what the verifier is configured to accept.
  4. Truncated or mangled? A signed token has exactly two dots. A stray line break or space from copy and paste breaks the signature.

Sources and further reading

Figures checked on 3 October 2026.

Do it now, free, in your browser. Your files are not uploaded.

Read what is inside a JSON Web Token, and check whether it has expired.

Frequently asked questions

What are the three parts of a JWT?
The header (algorithm and type), the payload (the claims) and the signature, each base64url-encoded and separated by dots.
Can anyone read the contents of a JWT?
Yes. In a signed JWT the payload is only encoded, not encrypted, so anyone holding the token can decode it. Do not put secrets in it.
Does decoding a JWT prove it is valid?
No. Decoding shows what the token claims. Only verifying the signature with the right key, and checking the claims, shows it is genuine and still valid.
What do exp and iat mean?
exp is the expiration time and iat is when the token was issued, both as seconds since 1 January 1970 UTC. A token must not be accepted on or after its exp.
Is it safe to paste a real JWT into an online decoder?
Only if the decoder runs in your browser and does not send it anywhere. A token can identify a user and may still be valid, so treat real ones like passwords.
What is the "alg: none" attack?
An attacker changes the header to say no signature is used, and a careless library accepts the token without checking any signature. RFC 8725 recommends only accepting an explicit list of algorithms.