Skip to content
FastUtil
Menu

How to Read a JWT: Header, Payload and Claims Explained

By FastUtil Team · Published · Updated

A JSON Web Token (JWT) looks like a random string, but it is three readable pieces joined by dots. You can read the first two without any key, which makes a JWT easy to inspect when you debug a login problem.

The three parts

A JWT has the form header.payload.signature. Each part is Base64URL-encoded, which is Base64 with - and _ instead of + and / and usually no = padding.

Here is a well-known sample token:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Decoding the first segment gives the header, which says how the token is signed:

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

HS256 means HMAC with SHA-256. The typ field is just a label saying this is a JWT.

Decoding the second segment gives the payload, which holds the claims:

{"sub":"1234567890","name":"John Doe","iat":1516239022}

The third segment is the signature. It is a hash computed from the first two parts and a secret (or a private key), so a server can tell whether the token was changed. It is not readable text.

What the common claims mean

RFC 7519 defines a short list of registered claims. None are required, but you will meet these most often:

  • iss (issuer): who created the token, for example your auth server's URL.
  • sub (subject): who the token is about, usually a user ID.
  • aud (audience): who the token is meant for. A service should reject tokens not addressed to it.
  • exp (expiration time): the moment after which the token must not be accepted.
  • nbf (not before): the moment before which the token must not be accepted.
  • iat (issued at): when the token was created.
  • jti (JWT ID): a unique ID, useful for revoking or detecting replays.

Anything else, like name or role, is a custom claim defined by the application that issued the token.

Turning exp, iat and nbf into dates

The three time claims are Unix timestamps in seconds, not milliseconds. In the sample, iat is 1516239022, which is 18 January 2018, 01:30:22 UTC. A quick way to check a token is to paste each time claim into a Unix timestamp converter and compare it with the current time.

If the converted date comes out in the year 50000 or so, the value was in milliseconds, which means the issuer is not following the JWT standard. If exp is earlier than now, the token has expired, and that is the most common reason for an unexpected "unauthorized" error. For more on the units, see our guide to Unix timestamps.

Decoding is not verifying

Anyone can decode a JWT, because the header and payload are encoded, not encrypted. Decoding tells you what the token claims. It does not tell you the claims are true. Only checking the signature with the correct key proves the token was issued by the party you trust and has not been altered.

Three rules follow from this:

  • Never put secrets, passwords or private data in a JWT payload, since anyone holding the token can read it.
  • Always verify the signature on the server before trusting any claim, and check exp, nbf, iss and aud.
  • Reject tokens that use "alg":"none" unless you deliberately allow unsigned tokens, and pin the algorithms you accept instead of trusting whatever the header says.

A decoder like our JWT decoder is for inspection only. It runs in your browser and does not verify signatures.

Troubleshooting a token that will not decode

  • It has five parts, not three. That is an encrypted token (JWE). The payload cannot be read without the decryption key.
  • An error about invalid characters. The token may include a Bearer prefix, quotes, or a line break copied with it. Paste only the token itself.
  • The JSON looks garbled. One segment may be truncated. Check that you copied the whole string, since tokens are often cut off by logs and terminals.
  • You want to read a segment by hand. Paste it into a Base64 decoder with URL-safe mode on.

Quick summary

A JWT is header, payload and signature. The first two are readable by anyone, the time claims are Unix seconds, and a decoded token is only trustworthy after the signature has been verified on the server.

Try it: Paste a token into the JWT decoder.

Related tools

  • JWT Decoder: Decode a JSON Web Token locally to read its header, payload and expiry without sending it anywhere.
  • Base64 Encoder & Decoder: Encode text to Base64 or decode Base64 back to text, with full Unicode and URL-safe support.
  • Unix Timestamp Converter: Convert epoch timestamps to readable dates and dates back to timestamps, in any common unit.