JSON Web Token (JWT): How the Payload Works

JWT (JSON Web Token) is one of the most widely used mechanisms today for authentication and secure information exchange between systems. The name already gives away the connection to this blog’s theme: at the center of a JWT, there’s a JSON payload. This post explains how that structure works, without going deep into cryptography, focusing on how JSON fits into the picture.

The structure of a JWT

A JWT is a string split into three parts, separated by dots.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiQW5hIiwiaWF0IjoxNzM3MDAwMDAwfQ.4f8h3k...

Those three parts are:

header.payload.signature

Each of the first two parts (header and payload) is, in fact, a JSON object encoded in Base64URL. The third part is the signature, which guarantees the token hasn’t been tampered with.

Decoding the header

The header is always a small JSON, indicating the signing algorithm used and the token’s type.

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

alg indicates the algorithm (HS256 is one of the most common), and typ simply confirms it’s a JWT.

Decoding the payload

The payload is where the actual data the token carries lives.

// json
{
  "name": "Ana",
  "sub": "12345",
  "iat": 1737000000,
  "exp": 1737003600
}

There are a few standardized fields (called “registered claims”) that show up frequently:

  • sub (subject): identifies the token’s “owner,” usually the user’s ID
  • iat (issued at): Unix timestamp of when the token was generated
  • exp (expiration): Unix timestamp of when the token expires
  • iss (issuer): who issued the token
  • aud (audience): who the token is intended for

Beyond these, you can add any custom field (like name in the example above), since it’s just a regular JSON object.

A critical point: the payload isn’t encrypted

This surprises a lot of beginners: a JWT’s header and payload are only encoded in Base64URL, not encrypted. Base64 is a way of representing binary data as text, not a security mechanism, it can be decoded by anyone without needing any key.

// javascript
const encodedPayload = "eyJuYW1lIjoiQW5hIiwiaWF0IjoxNzM3MDAwMDAwfQ";
const decodedPayload = JSON.parse(atob(encodedPayload));

console.log(decodedPayload); // { name: "Ana", iat: 1737000000 }

Anyone who has access to the token can read the payload’s content, without needing a password or secret key. Never put sensitive data (passwords, card numbers, confidential information) in a JWT’s payload.

So what does the signature actually guarantee?

The signature guarantees integrity, not confidentiality. It lets the server confirm the token hasn’t been altered after it was generated (for example, someone trying to change the sub to impersonate another user), but it doesn’t prevent the content from being read by anyone.

If you need to guarantee the token’s content is secret, there’s a variation called JWE (JSON Web Encryption), which actually encrypts the payload, but it’s much less common than the traditional JWT (JWS, JSON Web Signature).

A practical example: decoding a JWT in JavaScript

// javascript
function decodeJWT(token) {
  const [encodedHeader, encodedPayload] = token.split('.');

  const header = JSON.parse(atob(encodedHeader));
  const payload = JSON.parse(atob(encodedPayload));

  return { header, payload };
}

const { header, payload } = decodeJWT(myToken);
console.log(payload.exp); // expiration timestamp

Notice this only decodes the token, it doesn’t validate the signature. Validating the signature requires the secret key (or public key, depending on the algorithm) and is usually done with a specific library (like jsonwebtoken in Node.js), never manually.

Quick checklist

  • Confirmed that no sensitive data is being put in the JWT’s payload?
  • Validating the token’s signature on the server before trusting its content (not just decoding it)?
  • Checking the exp field to reject expired tokens?
  • Aware that anyone can decode (not decrypt) a JWT’s payload?

If you want to check the structure of a JWT’s decoded JSON, paste the result into JSON Validator to visualize it better.