~/blog/jwt-claims-reference

> JWT claims reference: iss, sub, aud, exp, nbf, iat explained

· jwt · auth · tokens

A JSON Web Token is three base64url-encoded segments separated by dots: header.payload.signature. The payload is a JSON object, and its keys are claims. RFC 7519 reserves seven short names as "registered claims"; everything else is custom. This is a reference for the standard seven.

iss — issuer

The party that issued the token. Usually the URL of the authorization server: https://auth.example.com. Clients should validate iss matches the expected issuer; otherwise a token minted by a malicious but trusted-to-you server can impersonate a token from the real one.

In OAuth 2 / OIDC, the issuer's discovery document at <iss>/.well-known/openid-configuration tells you where to fetch the signing keys — so trusting iss implicitly trusts the key-discovery path too.

sub — subject

The identifier for the principal the token is about, usually a user ID or service account ID. Scoped to the issuer: a sub of 1234 from auth.example.com is a different principal than sub of 1234 from auth.other.com.

Never use sub as a display name; it is an identifier, not a label. Never put PII in sub unless you own the token's entire lifecycle.

aud — audience

The recipients the token is intended for. Either a string (one audience) or an array (multiple). A resource server MUST reject a token whose aud does not include its own identifier — the audience check is what prevents a token issued for service A from being replayed against service B.

Common bug: using the client ID as audience when you mean the resource server. The audience should be the API's canonical URL or identifier, not the calling app's.

exp — expiration

Seconds since epoch at which the token becomes invalid. Required on any non-trivial token. Tokens with no exp live forever — they are revocable only by key rotation.

Validate with a small clock skew tolerance (commonly 30–60 seconds) to handle the case where the issuer's clock is slightly ahead of the resource server's. Beyond that, refuse.

nbf — not before

Seconds since epoch before which the token is not valid. Rare in practice but useful for pre-issuing tokens that activate later (e.g. a trial that starts at a specific date). Resource servers MUST enforce it or tokens can be replayed before their activation window.

iat — issued at

Seconds since epoch at which the token was issued. Not a validity boundary by itself — iat alone says nothing about whether the token is currently valid. Use it for audit, rate-limit-reset, or re-authentication prompts ("sensitive action: please re-enter your password, this session is older than 30 minutes").

iat in the future is suspicious but not necessarily invalid. Some implementations reject tokens where iat > now + skew.

jti — JWT ID

A unique identifier for the token. Useful for:

  • Replay detection (resource server keeps a bloom filter of seen jtis).
  • Revocation lists (a specific token ID is marked invalid).

Not required. Only meaningful if the resource server actually tracks it.

The signing + validation flow

A resource server receiving a JWT does, in order:

  1. Parse the three segments.
  2. Decode the header, read alg and kid.
  3. Fetch the public key matching kid (cached from the issuer's JWKS endpoint).
  4. Verify the signature using the algorithm.
  5. Decode the payload.
  6. Validate iss, aud, exp, nbf, iat.
  7. Apply any application-specific checks (scopes, custom claims).

Skipping any step is a vulnerability. In particular, not validating alg is the infamous "alg=none" attack — if your library trusts the header's algorithm claim without whitelisting, an attacker submits alg=none and an empty signature and is trusted.

Decode a JWT and inspect its claims →

Further reading