Reading exp, iat, and payload claims from a JWT
The three-part structure of a JWT, what the standard claims mean, and what to check first when debugging an authentication failure.
The structure of a JWT
A JWT consists of three dot-separated parts: header, payload, and signature.
The header and payload are JSON encoded with URL-safe Base64. That is encoding, not encryption, so anyone holding the token can read them. This is the first thing to understand about JWTs.
The signature is the header and payload signed with a secret key. It does not hide the contents; it proves they have not been altered. If somebody edits a role claim to admin, the signature no longer matches and the server rejects the token.
What the standard claims mean
Values inside the payload are called claims. The standard ones are as follows.
- exp (expiration time): when the token stops being valid, as a Unix timestamp in seconds.
- iat (issued at): when the token was created.
- nbf (not before): the token must not be accepted before this time, used for scheduled access.
- sub (subject): who the token is about, normally a user identifier.
- iss (issuer): which authority issued it, useful when several authentication servers exist.
- aud (audience): which service is supposed to accept this token.
A debugging order that works
When a 401 or 403 appears, decoding the token usually exposes the cause quickly.
Check exp first. It is a Unix timestamp, so convert it to a date to read it. If the time has passed, look at the refresh logic. A surprising share of authentication incidents end right here.
Next look at authorization claims such as role, scope, or permissions. When login works but one feature is blocked, this is almost always where the answer is.
Then check iss and aud. Sending a token issued by a development server to production happens more often than anyone admits, and these two claims reveal it immediately.
What must never go in the payload
Because the payload is readable by anyone holding the token, sensitive values placed there are effectively public. Passwords, national identifiers, card numbers, and detailed internal structure must stay out.
Size matters too. The token travels with every request, so a payload carrying an entire user profile inflates every single call. Keep an identifier and the minimum authorization data, and fetch the rest when it is actually needed.
Decoding is not verification
Being able to decode a JWT with an online tool says nothing about whether it is valid. Decoding merely undoes Base64; verification checks the signature against the secret key and is a separate step.
Verification must happen on the server. Reading the payload on the client to adjust what is displayed is fine, but it must never decide authorization, because a user can edit the payload and send whatever they like.
A server that accepts a token whose header sets alg to none has a serious vulnerability, since anyone can then mint a token with any privileges. Servers should pin the accepted algorithm explicitly.