DevBento logoDevBento
Tools/JWT Decoder/JWT Claims Explained: exp, iat, nbf, and Standard

JWT Claims Explained: exp, iat, nbf, and Standard

Understand JWT token claims including exp, iat, nbf, iss, sub, aud. Covers clock skew, token refresh patterns, and common mistakes.

Related Tools
jwtJWT Decoder
Decode and inspect JSON Web Tokens in your browser. View the header, payload claims, and expiration status without sending your token to any server.
jwtJWT Generator
Generate signed JWT tokens for testing with HS256 and RS256 signing. Build tokens with standard claims, custom claims, and configurable expiration.

What JWT Claims Do

A JWT is three base64url-encoded segments separated by dots: header.payload.signature. The payload contains claims, which are key-value pairs that carry identity and authorization data. Every claim is visible to anyone who has the token. There is no encryption, only a signature that verifies the token was issued by a trusted party.

The claims fall into three categories:

The Time Claims: iat, nbf, exp

These three claims form a token’s lifecycle:

iat ──────────── nbf ──────────── token active ──────────── exp
                  β”‚                                        β”‚
                  └── token starts being valid             └── token expires

iat (Issued At)

The Unix timestamp when the token was created. This is informational. It does not affect validation unless your application logic uses it to enforce a maximum token age.

{
  "iat": 1735603200
}

1735603200 = January 1, 2025 at 00:00:00 UTC.

nbf (Not Before)

The Unix timestamp when the token becomes valid. If a token arrives with an nbf in the future, the server should reject it. This is rare in practice. Most systems set nbf equal to iat.

{
  "nbf": 1735603200
}

exp (Expiration)

The Unix timestamp when the token becomes invalid. This is the key time claim. The server must reject any token with exp in the past.

{
  "exp": 1735689600,
  "iat": 1735603200
}

The difference is 86400 seconds (24 hours). This token has a one-day lifetime.

Standard Registered Claims

Beyond the time claims, the JWT spec defines several standard claims:

Claim Name Purpose Example
iss Issuer Who created the token "https://api.example.com"
sub Subject Who the token is about "user_12345"
aud Audience Who the token is for "https://app.example.com"
exp Expiration When the token expires 1735689600
nbf Not Before When the token becomes valid 1735603200
iat Issued At When the token was created 1735603200
jti JWT ID Unique token identifier "abc-123-def"

iss (Issuer): Identifies who created the token. Your auth server should validate this to prevent tokens from other issuers from being accepted.

sub (Subject): The entity the token represents. Typically a user ID or service account name. Use this in your authorization logic to identify who is making the request.

aud (Audience): Who the token was issued for. If your system has multiple services (e.g., API gateway, user service, payment service), each should verify the aud claim matches its own identifier. This prevents a token intended for one service from being replayed against another.

jti (JWT ID): A unique identifier for the token. Use this for token revocation. Store the jti in a denylist when the user logs out or the token is revoked.

Clock Skew: Why Tokens Get Rejected Too Early

Servers’ clocks are never perfectly synchronized. If the auth server’s clock is 30 seconds ahead of the API server’s clock, a token with exp = 1735689600 might be validated against a server that thinks it is already 1735689631. The token is technically expired on the API server even though the auth server says it is valid.

The fix is a leeway window:

// Node.js with jsonwebtoken
jwt.verify(token, secret, { clockTolerance: 30 }); // 30 seconds tolerance

// Go with golang-jwt
token, err := jwt.Parse(tokenString, keyFunc,
    jwt.WithLeeway(30 * time.Second),
)

A 30-60 second leeway is standard. Do not set it to zero or you will see intermittent 401 errors that are difficult to debug.

Common Mistakes

Using exp with seconds vs milliseconds

Some libraries use seconds (RFC 7519 standard), others use milliseconds. A token with exp: 1735689600 (seconds) looks like year 56935 if interpreted as milliseconds. Verify your library’s expectation.

Setting exp too far in the future

A token with a 30-day lifetime means a stolen token is usable for 30 days. Access tokens should expire in 15-60 minutes. Use refresh tokens for longer sessions.

Missing aud validation

If your API does not check the aud claim, a token issued for a different service can be used against your endpoint. Always validate iss and aud.

Storing sensitive data in claims

Claims are readable by anyone with the token. Do not put passwords, SSNs, or private keys in JWT claims. Use opaque references instead.

Decoding the Example Token

Paste the example token into JWT Decoder to see all claims decoded. The payload contains:

{
  "iss": "https://api.example.com",
  "sub": "user_12345",
  "aud": "https://app.example.com",
  "exp": 1735689600,
  "iat": 1735603200,
  "nbf": 1735603200,
  "role": "admin",
  "permissions": ["read", "write", "delete"]
}

The token was issued at midnight UTC on January 1, 2025, expires 24 hours later, and grants admin access to user_12345.

πŸ”’

Nothing you paste leaves this tab. Every tool runs entirely in your browser β€” no upload, no server, no account.

Β© 2026 devbento.dev Β· built local-firstChangelog