Blog

How to decode a JWT token

What's inside a JSON Web Token, what each claim means, and how to inspect one without fooling yourself about what decoding proves.

February 7, 2026

Your API returns 401 Unauthorized, and the only clue is a 300-character string starting with eyJ. It looks like line noise, but it’s readable JSON once you decode it. Here’s what’s inside and what to look for.

What is a JWT

A JSON Web Token (JWT, often said “jot”) is a compact, URL-safe way to pass a few facts, called claims, from one system to another. You usually meet them at login. You sign in, the server hands your app a token, and your app sends it with every request after that to prove who you are.

JWTs are defined in RFC 7519 and are used by OAuth 2.0, OpenID Connect and plenty of home-grown auth setups. A signed JWT carries its own data and a signature. That means the server can check it with a key instead of looking up a session in a database on every request.

The three parts of a JWT

A JWT is three chunks joined by dots: header.payload.signature. Each chunk is Base64URL-encoded, a URL-safe variant of Base64. That encoding is why they all look like gibberish.

Text
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9                          header
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNjE2MjM5MDIyfQ   payload
.jBlavbnSLYeudUv3JNScKaJiQqkOclFRjfEp6Y7BRDc                   signature

A real token is one long line with no spaces. It’s split up here only so the parts can be labelled.

Header

The header says what kind of token this is and how it was signed. The two algorithms you’ll see most are HS256 (HMAC with SHA-256, where one shared secret both signs and verifies) and RS256 (an RSA signature, where a private key signs and a public key verifies).

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

Payload

The payload holds the claims: facts about the user and about the token itself. The example token above decodes to this:

JSON
{
  "sub": "1234567890",
  "name": "Alice",
  "iat": 1616239022
}

RFC 7519 defines a handful of registered claims with short names. All of them are optional:

ClaimMeaning
issIssuer: who created the token
subSubject: usually the user ID
audAudience: which service the token is meant for
expExpiration time, as a Unix timestamp in seconds
nbfNot before: the token isn’t valid until this time
iatIssued at: when the token was created
jtiJWT ID: a unique ID for this token

Everything else is up to the issuer. Public claims such as name or email are registered with IANA or use names unlikely to clash. Private claims such as role are whatever the issuer and your app agree on.

Signature

The signature is calculated from the encoded header and payload, using the algorithm named in the header. For HS256 it looks like this:

Text
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

Change one character of the header or payload and the signature stops matching. So nobody can promote themselves to admin by editing their token, unless they also have the key. (The example above was signed with the secret your-256-bit-secret. Please don’t use that one.)

Token expiration

The exp claim is a Unix timestamp in seconds. After that moment, the server should reject the token. Access tokens usually last 15 minutes to an hour, and refresh tokens can last days or weeks.

When you’re chasing a 401, check exp first. More often than you’d like, the token simply expired while you were reading the docs.

How to use the JWT decoder

  1. Open the JWT decoder, paste the whole token with all three parts, and select Decode.
  2. The Header and Payload appear as formatted JSON, each with its own Copy button.
  3. Time claims (iat, exp, nbf and auth_time) get a readable date next to the number, both in ISO 8601 and in your local time.
  4. If exp is in the past, you’ll see a “This token has expired” warning.
  5. The Signature is shown as the raw encoded string. The decoder doesn’t verify it, because that needs the secret or public key, and you shouldn’t be pasting those into websites.

Decoding happens in your browser, so the token isn’t sent to any server.

Security notes

  • The payload isn’t encrypted. It’s only encoded, so anyone holding the token can read it, as you just did. Never put passwords, card numbers or other secrets in a payload.
  • Decoding isn’t verifying. Your server must check the signature, plus exp, nbf, iss and aud, before it trusts any claim. An unverified JWT is just JSON that anyone could have typed.
  • Pin the algorithm. Some libraries have accepted tokens with "alg": "none", which means no signature at all. Tell your verifier exactly which algorithms you expect.
  • Treat tokens like passwords. A valid token is a key to the account until it expires, so don’t paste production tokens into tools you don’t trust.

Need data from a webpage as JSON?

PulpMiner turns any public page into structured JSON and can save it as a live API. See it work on a demo page, no sign-up.

Try it on a demo page