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.
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:
| Claim | Meaning |
|---|---|
iss | issuer: who created the token |
sub | subject: who the token is about (often a user ID) |
aud | audience: who the token is meant for |
exp | expiration time: from this moment the token must not be accepted |
nbf | not before: the token must not be accepted before this time |
iat | issued at: when it was created |
jti | JWT 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"
- Expired? Convert
expto a date and compare it with now. Clock skew between servers is a frequent culprit. - Wrong audience or issuer? Compare
audandisswith what your service expects. - Wrong algorithm or key? Check
algin the header against what the verifier is configured to accept. - 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?
Can anyone read the contents of a JWT?
Does decoding a JWT prove it is valid?
What do exp and iat mean?
Is it safe to paste a real JWT into an online decoder?
What is the "alg: none" attack?
Related guides
Tools used in this guide
They run in your browser, so nothing is uploaded.