A JSON Web Token is a compact, signed way to represent claims (facts) about a user or a grant, made of three base64url-encoded parts separated by dots: header.payload.signature.
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0IiwibmFtZSI6IkFsaWNlIn0.4pZ9...
└──── header ────┘ └──────────── payload ────────────┘ └ signature ┘
Decoded, the header identifies the signing algorithm and token type:
{ "alg": "HS256", "typ": "JWT" }
And the payload is just JSON claims:
{ "sub": "1234", "name": "Alice", "iat": 1710000000, "exp": 1710003600 }
A handful of claim names are standardized (registered claims) and worth recognizing on sight:
| Claim | Meaning |
|---|---|
sub | Subject — the user or entity this token is about |
iss | Issuer — who created and signed this token |
aud | Audience — who this token is intended for |
exp | Expiration time (Unix timestamp) — the token is invalid after this |
iat | Issued at (Unix timestamp) |
nbf | Not before — the token isn't valid until this time |
Two things people get wrong constantly, and both matter operationally, not just academically:
exp matters far more than it looks like it should. A JWT can't be "revoked" the way a server-side session record can be deleted — it's cryptographically valid until the moment it expires, full stop, even if the user's account is disabled five minutes after the token was issued. This is exactly why real systems pair a short-lived access token (a JWT, minutes to an hour) with a longer-lived refresh token stored server-side, which can be revoked, and which is used to mint new access tokens without forcing the user to log in again.