ToolNest logoToolNest.

How to Read a JWT Token

A JWT (JSON Web Token) is three Base64URL-encoded parts separated by dots: header.payload.signature. To read one, split it on the dots and Base64-decode the first two parts — you'll see JSON. The header names the signing algorithm; the payload carries claims like who you are and when the token expires. Decode any token free with our JWT decoder.

The short answer

Every JWT has the same anatomy: two dots dividing three Base64URL strings. The first segment is the header — metadata saying which algorithm signed the token. The second is the payload — the actual data, called claims: user id, name, permissions, issue and expiry times. The third is the signature — cryptographic proof the first two have not been tampered with. Reading a token means decoding the first two segments from Base64URL into text, which reveals plain JSON. The signature is not meant to be read; it is meant to be verified, and only someone holding the secret key can do that. Anyone can read a JWT — that surprises most beginners, and it matters for security, as the encryption section below explains.

Part 1: the header

The header is small and boring, which is exactly its job. Decoded, a typical header looks like {"alg":"HS256","typ":"JWT"}: the token type (always JWT) and the signing algorithm (here HS256, HMAC with SHA-256). The alg field is the critical one — it tells the verifier which cryptographic recipe to use when checking the signature. You will also meet RS256 (RSA signatures, where verification uses a public key instead of a shared secret) and ES256 (elliptic-curve variant). One famous security disaster came from this field: the "alg: none" attack, where servers were tricked into accepting unsigned tokens because they trusted the header blindly. Modern libraries reject alg:none by default, but the lesson stands — the header describes the token; it does not protect it.

Part 2: the payload

The payload is where the meaning lives. It is a JSON object of claims — name/value pairs about the subject of the token. Seven claims are registered standards: iss (issuer, who created the token), sub (subject, usually the user id), aud (audience, who the token is for), exp (expiry, as a Unix timestamp), nbf (not-before, the token is invalid earlier), iat (issued-at, when it was minted), and jti (a unique token id, useful for revocation lists). Beyond these, issuers add whatever they need: name, email, roles, permissions. Our worked example below carries sub, name, admin, iat, and exp. Note that exp and iat are Unix timestamps — seconds since 1970 — which is why a token can encode "valid for one hour" as two integers with no date strings at all.

Part 3: the signature

The signature is what makes a JWT trustworthy rather than merely readable. For HS256 it is computed as HMAC-SHA256 over the string "base64url(header) + '.' + base64url(payload)", keyed with a secret only the issuer knows. Change even one character of the header or payload and the signature stops matching — verification fails, and the server rejects the token. That is the whole security model: the payload is public, the signature is the seal. With RS256 the math uses asymmetric keys instead — the issuer signs with a private key and anyone can verify with the public key, which is how "sign in with" providers work. You cannot verify an HS256 signature without the secret, and you should never try to guess it: that is precisely the attack the algorithm is designed to survive.

A real token, decoded step by step

Here is a genuine HS256 token, generated for this article with the secret "your-256-bit-secret": eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiYWRtaW4iOmZhbHNlLCJpYXQiOjE3OTEwNzIwMDAsImV4cCI6MTc5MTA3NTYwMH0.K6JYxsYvfZJ71IJ2ocd0NMwpR-kOFR0KFu_2Hg0e8fk — Step 1: split on the dots. You get a 36-character header segment, a 115-character payload segment, and a 43-character signature. Step 2: Base64URL-decode the header (pad it back to a multiple of 4 first — most decoders do this automatically). It reveals {"alg":"HS256","typ":"JWT"}. Step 3: decode the payload the same way. It reveals {"sub":"1234567890","name":"Jane Doe","admin":false,"iat":1791072000,"exp":1791075600}. Step 4: read the claims — this token belongs to user 1234567890 (Jane Doe, not an admin), was issued at timestamp 1791072000, and expires at 1791075600, exactly one hour later. The signature segment stays opaque: without the secret, all you can do is admire its 43 characters.

Reading the timestamps inside

The iat and exp claims are the reason JWT readers keep meeting enormous integers. 1791072000 is not a user id — it is a Unix timestamp: seconds since January 1, 1970, always in UTC. Convert it and you get October 4, 2026 at 00:00 UTC; add 3,600 seconds and exp lands at 01:00 UTC. This is how sessions expire without any server-side state: the server mints the token with exp set one hour out, and every later request is accepted or rejected by comparing exp against the current time. If you are debugging "my token stopped working," decode it and check exp first — expiry is the cause more often than all other JWT errors combined. Clock skew between servers can also bite: if the issuer's clock runs minutes ahead of the verifier's, a fresh token can look prematurely expired.

What JWTs do not do: encryption

The most dangerous misunderstanding about JWTs is thinking they are encrypted. A standard JWT is signed, not encrypted — the technical term is JWS (JSON Web Signature). The payload is merely Base64URL-encoded, which is an encoding, not encryption: anyone who intercepts the token can decode and read every claim, no key required. Never put passwords, API secrets, or personal data beyond what the app needs into a payload. If the payload must stay confidential, you need JWE (JSON Web Encryption), which actually encrypts the claims — but JWE is rare in practice. The standard pattern is: keep payloads minimal (ids and roles, not secrets), transmit tokens only over HTTPS, and store them where JavaScript cannot reach them (httpOnly cookies) to blunt cross-site scripting theft.

Common errors when reading tokens

Four failures cover nearly every JWT headache. "Invalid signature" means the content was altered, the wrong secret was used for verification, or — most commonly — the token was copied with a character missing or an extra whitespace. "Token expired" means the current time is past exp; the fix is a fresh login or a refresh-token flow, not clock-fiddling. "Malformed token" usually means the string does not have exactly three dot-separated segments — often a truncated paste or a token wrapped across lines. And silent weirdness — a token that decodes fine but the server rejects — usually traces to claims: wrong aud, an nbf in the future, or an issuer the server does not recognize. When debugging, decode first and read the claims before suspecting the cryptography; the answer is in the payload nine times out of ten.

JWT vs session cookies: when each wins

JWTs are often compared to old-fashioned session cookies, and the tradeoff is about state. A session cookie is a random id; the server looks up everything in a database on each request — simple, instantly revocable, but it costs a database hit every time and complicates multi-server setups. A JWT is self-contained: the server verifies the signature and trusts the claims, no lookup needed — which scales beautifully across microservices and mobile APIs. The price is revocation: you cannot easily cancel one JWT without keeping a denylist, which reintroduces the state you were avoiding. Short expirations (minutes to an hour) plus refresh tokens are the standard compromise. Neither is universally better — sessions win for admin panels where instant lockout matters; JWTs win for APIs serving millions of stateless requests.

Decode any token in one click

Paste any JWT into our free JWT decoder to see the header and payload as formatted JSON, with the timestamps converted to human dates and expiry flagged automatically. It runs entirely in your browser — your tokens never leave your device, which matters because a token is a credential. Since payloads are JSON, our guide to what JSON is fills in any gaps, and JSON formatter vs validator explains the tooling around it. And whenever a claim shows a giant integer, you now know it is a Unix timestamp.

Do it in one click

Decode any JWT free — header, payload, and human-readable dates.

Open the Free Tool →