Complete reference for JWT (JSON Web Token) registered claims, OpenID Connect claims, custom claims, validation rules, and security best practices.
| Claim | Description |
|---|---|
iss | Identifies the principal that issued the JWT. Typically the auth server URL. |
sub | Identifies the principal that is the subject of the JWT β usually the user ID. |
aud | Identifies the recipients that the JWT is intended for. The API must check this. |
exp | The time after which the JWT MUST NOT be accepted. Critical for security. |
nbf | The time before which the JWT MUST NOT be accepted. Useful for deferred activation. |
iat | The time at which the JWT was issued. Used to determine the age of the token. |
jti | Unique identifier for the JWT. Prevents token replay attacks when combined with a blocklist. |
| Claim | Description |
|---|---|
name | End-user's full name in displayable form. |
given_name | Given name(s) or first name of the end-user. |
family_name | Surname(s) or last name of the end-user. |
email | End-user's preferred email address. |
email_verified | True if the end-user's email has been verified by the Provider. |
picture | URL of the end-user's profile picture. |
locale | End-user's locale as a BCP 47 language tag. |
zoneinfo | End-user's time zone from the IANA Time Zone Database. |
updated_at | Time the end-user's information was last updated. |
nonce | String value used to associate a Client session with an ID Token and to mitigate replay attacks. |
at_hash | Hash of the Access Token value. Used to validate the access_token. |
auth_time | Time when the end-user was authenticated. |
| Claim | Description |
|---|---|
scope | OAuth 2.0 scopes granted to the token. Defines what resources the token can access. |
roles | Non-standard but widely used. Application roles assigned to the user. |
permissions | Fine-grained permissions. Used by Auth0, AWS Cognito, and others. |
azp | The client_id of the OAuth 2.0 Client that requested the token. Used with OIDC. |
acr | Level of authentication that occurred. Values defined by the deployment. |
amr | How the user was authenticated (password, OTP, biometric, etc.). |
| Claim | Description |
|---|---|
tenant_id | Multi-tenant app custom claim. Identifies the tenant/organization. |
org_id | Organization identifier used by Auth0, WorkOS, and similar platforms. |
plan | User's subscription tier. Common in SaaS billing-based access control. |
| Claim | Description |
|---|---|
Verify exp | Reject any token where exp < current time (in UTC seconds). Add small clock skew (30β60s). |
Verify iss | Must exactly match the expected issuer URL. Reject mismatches. |
Verify aud | Must contain your API's identifier. Reject tokens issued for other audiences. |
Verify signature | NEVER trust a JWT without verifying its cryptographic signature using the correct key/JWKS. |
Check nbf | If nbf is present, reject tokens used before this time. |
Check alg | Explicitly specify expected algorithm. Reject 'none' algorithm. Prefer RS256 or ES256 over HS256 for public APIs. |
| Claim | Description |
|---|---|
HS256 | Fast; uses a single shared secret for sign & verify. Only suitable when both parties are trusted (e.g., server-to-server). |
HS512 | Like HS256 but with 512-bit hash output. Marginally stronger for symmetric use cases. |
RS256 | Most widely supported asymmetric algorithm. Sign with private key, verify with public key. Use this for public APIs and OIDC. |
RS512 | RS256 with SHA-512. Stronger hash but same RSA security level. Marginally slower. |
ES256 | Compact, fast asymmetric algorithm. Smaller keys than RSA for equivalent security. Recommended for new systems. |
PS256 | More secure padding than RS256 (probabilistic). Required by FAPI (Financial-grade API) and advanced OIDC profiles. |
EdDSA | Modern elliptic curve algorithm. Fastest, smallest signatures. Use with jose library. Not universally supported yet. |
A JWT consists of three Base64URL-encoded parts separated by dots: Header.Payload.Signature
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20iLCJzdWIiOiJ1c2VyXzEyMyIsImF1ZCI6Imh0dHBzOi8vYXBpLmV4YW1wbGUuY29tIiwiZXhwIjoxNzM1Njg5NjAwLCJpYXQiOjE3MzU2MDMyMDAsInNjb3BlIjoicmVhZDp1c2VycyJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
{"alg":"RS256","typ":"JWT"}Algorithm and token type
{"iss":"https://auth.example.com","sub":"user_123","exp":1735689600,...}Claims - the data
RSASHA256(base64url(header) + '.' + base64url(payload), privateKey)Cryptographic verification
Use the JWT Encoder/Decoder to interactively build, sign, and inspect JWT tokens.
exp (expiration time) is when the token expires and must not be accepted after this time. nbf (not before) is when the token becomes valid β it must not be accepted before this time. iat (issued at) records when the token was issued β useful for determining token age. All three use NumericDate format (seconds since Unix epoch).
Access tokens should be short-lived: 5-60 minutes for most apps, 1-24 hours for APIs. Refresh tokens can be longer: days to weeks. Short expiration limits the damage from token theft. Never store sensitive data in JWT payloads since they are base64url-encoded (not encrypted) and can be decoded by anyone.
sub (subject) identifies the principal (typically a user ID) the JWT is about. It should be unique within the issuer's context. Use a stable, non-reassignable identifier (like a UUID or numeric ID) rather than a username or email, which can change.
Yes, for stateless authorization. Include roles/permissions in custom claims (e.g., 'roles': ['admin', 'user']). However, keep tokens lightweight β don't include everything. For fine-grained permissions, consider a reference token pattern where the JWT contains a session ID and you look up permissions server-side.