JWT, explained: claims, signature, and expiry
How a JWT works, what claims such as sub, iss, aud, and exp mean, and what to watch when APIs rely on tokens.
JWT (JSON Web Token) became the default format for access tokens and ID tokens in modern APIs. Three base64 parts separated by dots: header, payload, signature. It looks transparent — and that is where many people only call atob() in the browser and believe they authenticated. A JWT is not encryption; it is a signed payload (or an encrypted one, in the case of JWE).
Anatomy of a token
Header: { "alg": "RS256", "typ": "JWT" }
Payload: { "sub": "user-123", "iss": "https://auth.example.com",
"aud": "my-api", "exp": 1710003600, "roles": ["ADMIN"] }
Signature: RSASSA-PKCS1-v1_5 over header.payloadClaims you have to validate
iss(issuer) — who issued it; it must match your authorization serveraud(audience) — which API or client the token was issued forsub(subject) — a stable identifier for the userexp/nbf— expiry and not-beforeiat— issued at; useful for spotting reused tokens
Signature and JWKS
With RS256, the API fetches public keys from the issuer’s JWKS endpoint, verifies the signature, and only then trusts the payload. Key rotation needs a short-TTL cache and a fallback when kid changes.
When JWT works well
- Stateless APIs that validate the token locally
- Microservices that trust the same issuer
- Short-lived tokens plus a refresh token on the backend
Common mistakes
- Trusting the payload without validating the signature
- Accepting HS256 with a weak secret shared across 12 services
- Ignoring exp, or using infinite clock skew
- Putting PII or sensitive data in the payload (a JWT is not a secret)
- An access token that lasts for days “so the session does not expire”
- Not revoking the refresh token when the user changes the password
How Gatekeeper ID helps
The Spring Boot SDK validates the JWT via the tenant’s JWKS, extracts roles and permissions, and applies RBAC before the controller. You do not reimplement the parser, clock skew, or key rotation — you configure application.yml and protect endpoints.
Protocol context: OAuth2 vs OpenID Connect.
Conclusion
A JWT is a contract between issuer and resource server. Treat validation as critical security code — or use a maintained library or SDK that already implements RFC 7519 correctly.