JWT Claims Explained

A complete reference for registered, public, and private claims in JSON Web Tokens

1. What Are JWT Claims?

Claims are the key-value pairs stored in the JWT payload. They represent statements about an entity (typically a user) and additional metadata. The word "claim" is used because the token claims something to be true — for example, that the user's ID is "12345" or that the token expires at a specific time.

A decoded JWT payload might look like this:

{
  "iss": "https://auth.example.com",
  "sub": "user_12345",
  "aud": "https://api.example.com",
  "exp": 1735689600,
  "iat": 1735686000,
  "name": "Alice Johnson",
  "role": "editor",
  "permissions": ["read", "write"]
}

In this example, iss, sub, aud, exp, and iat are registered claims defined by the JWT specification. name, role, and permissions are private claims chosen by the application developer.

2. Registered Claims (RFC 7519)

Registered claims are predefined by the JWT specification. They are not mandatory, but when present, they must follow the defined semantics. All registered claim names are intentionally kept to three characters to keep tokens compact.

iss — Issuer

Identifies the principal that issued the JWT. This is typically a URL or string identifying your authentication server.

"iss": "https://auth.example.com"

Use case: When multiple services issue tokens, the consumer can check iss to confirm the token came from a trusted authority. If the issuer doesn't match the expected value, reject the token.

sub — Subject

Identifies the principal that is the subject of the JWT. In most authentication systems, this is a unique user identifier.

"sub": "user_12345"

Use case: The backend reads sub to identify which user made the request. This value should be unique within the issuer's domain and is typically a database ID or UUID.

aud — Audience

Identifies the recipients that the JWT is intended for. Can be a single string or an array of strings.

"aud": ["https://api.example.com", "https://admin.example.com"]

Use case: An API server checks that its own identifier appears in the aud claim before accepting the token. This prevents tokens issued for one service from being used at another.

exp — Expiration Time

The time after which the JWT must not be accepted for processing. The value is a Unix timestamp (seconds since January 1, 1970 UTC).

"exp": 1735689600

Use case: The most critical claim for security. Short-lived access tokens (15 minutes to 1 hour) limit the damage if a token is compromised. Always validate this claim server-side.

Warning: Clock skew between servers can cause valid tokens to be rejected. Most libraries allow a small tolerance (e.g., 30 seconds) when validating expiration.

nbf — Not Before

The time before which the JWT must not be accepted. Like exp, this is a Unix timestamp.

"nbf": 1735686000

Use case: Useful for tokens that should only become valid at a future time, such as pre-issued tokens for scheduled access or delayed activation scenarios.

iat — Issued At

The time at which the JWT was issued. This can be used to determine the age of a token.

"iat": 1735686000

Use case: Servers can use iat to reject tokens that are too old, even if they haven't technically expired. Also useful for auditing and debugging.

jti — JWT ID

A unique identifier for the token. Used to prevent the JWT from being replayed.

"jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

Use case: The server stores seen jti values and rejects tokens with duplicate IDs. Essential for one-time-use tokens or when implementing token revocation.

3. Public Claims

Public claims are not registered in the JWT specification but are defined in the IANA JSON Web Token Claims Registry. They provide a collision-resistant namespace for commonly needed claims that go beyond the seven registered ones.

Common public claims from the IANA registry and OpenID Connect:

ClaimDescriptionSource
nameFull name of the userOpenID Connect
emailEmail addressOpenID Connect
email_verifiedWhether the email has been verifiedOpenID Connect
given_nameFirst nameOpenID Connect
family_nameLast nameOpenID Connect
pictureURL of the user's profile imageOpenID Connect
localeLocale string (e.g., "en-US")OpenID Connect
nonceString value to associate a session with an ID tokenOpenID Connect
at_hashAccess token hash valueOpenID Connect

If you need a custom claim that might be used across organizations, consider registering it with IANA. Alternatively, use a URI-based name (e.g., "https://example.com/claims/department") to avoid collisions with other systems.

4. Private Claims

Private claims are custom claims created by the application developer to share information between parties that have agreed on their meaning. These are the most flexible and the most commonly used in practice.

{
  "sub": "user_12345",
  "role": "admin",
  "department": "engineering",
  "permissions": ["read", "write", "delete"],
  "subscription_tier": "pro",
  "feature_flags": {
    "new_dashboard": true,
    "beta_api": false
  }
}

Keep payloads small. Every claim adds to the token size, and JWTs are sent with every HTTP request. Large tokens increase bandwidth usage and can exceed header size limits in some servers (typically 8 KB). Only include claims that the token consumer actually needs.

5. Claim Validation in Practice

Decoding a JWT is only the first step. For security, the server must validate claims before trusting the token. Here is the typical validation sequence:

  1. Verify the signature — Confirm the token hasn't been tampered with using the appropriate algorithm and key
  2. Check exp — Reject tokens that have expired (with a small clock-skew tolerance)
  3. Check nbf — If present, reject tokens that aren't yet valid
  4. Check iss — Verify the token was issued by a trusted authority
  5. Check aud — Confirm the token is intended for your service
  6. Validate custom claims — Check roles, permissions, or other application-specific claims

Tip: Most JWT libraries handle signature verification and standard claim validation automatically. Don't implement these checks from scratch — use a well-tested library for your language.

6. Common Claim Patterns

Role-Based Access Control (RBAC)

{
  "sub": "user_789",
  "roles": ["editor", "reviewer"],
  "org_id": "org_456"
}

The server checks the roles array to determine what the user can do. Including org_id enables multi-tenant authorization.

API Scopes (OAuth 2.0)

{
  "sub": "client_app_123",
  "scope": "read:users write:posts",
  "client_id": "mobile_app_v2"
}

The scope claim (a space-separated string) defines what API operations the token grants access to. This is the standard pattern used in OAuth 2.0 access tokens.

Session Metadata

{
  "sub": "user_12345",
  "sid": "session_abc",
  "ip": "192.168.1.100",
  "device": "Chrome/120 on macOS",
  "iat": 1735686000,
  "exp": 1735689600
}

Including session context in the token lets servers detect suspicious activity, such as a token being used from a different IP address or device than where it was issued.

7. Best Practices

  • Always set exp — Tokens without expiration are a permanent security risk if compromised. Use short lifetimes for access tokens (15 min to 1 hour).
  • Validate iss and aud — These claims prevent token misuse across services. A token issued by Service A should not be accepted by Service B unless explicitly intended.
  • Don't put sensitive data in claims — JWTs are encoded, not encrypted. Anyone with the token can read the payload. Never include passwords, credit card numbers, or secrets.
  • Keep tokens small — Only include claims the consumer needs. Large tokens slow down every API request and may hit header size limits.
  • Use standard claim names — Prefer registered and IANA-registered claim names over inventing your own. This improves interoperability.
  • Use jti for sensitive operations — For one-time actions like password resets or email verification, include a jti and track used token IDs server-side.

Inspect Your JWT Claims

Paste a token into our decoder to see all claims, formatted and color-coded.