exp (Expiration Time) Claim in a JWT
exp is the time after which the token must be rejected, written as seconds since the Unix epoch. It is the only claim that limits how long a leaked token stays useful, because a signed token cannot be recalled.
At a glance
- Claim
- exp (Expiration Time)
- Defined in
- RFC 7519 section 4.1.4
- Value type
- NumericDate: seconds since 1970-01-01T00:00:00Z, ignoring leap seconds
- Required
- Optional in RFC 7519. Required in an OpenID Connect ID token and an RFC 9068 access token.
- Sample value
- 1735693200, which is 2025-01-01 01:00:00 UTC
- In the decoder
- Explained by name and rendered as local time, with a live countdown, a lifetime progress bar and four expiry states.
In detail
A NumericDate is a plain JSON number counting seconds, not milliseconds, since the start of 1970 UTC. Non integer values are allowed but nobody uses them. RFC 7519 says implementations may allow a small leeway, normally no more than a few minutes, to absorb clock differences between the issuer and the verifier, and that leeway is a configuration value rather than something the token carries.
Expiry is the only revocation most JWT deployments have. Once a token is signed it is valid until exp passes, whether or not the session was ended, the password changed or the account deleted, because a verifier that checks only the signature never talks to the issuer. That is the trade being made for stateless verification, and it is why access token lifetimes are usually minutes while the refresh token that replaces them lives server side.
Choosing a lifetime is a balance between how often you are willing to make a round trip to the issuer and how long you can tolerate a stolen token working. Short lived access tokens with a longer lived refresh token is the standard answer. A token with no exp at all never stops working, and one with a lifetime of days is a credential you cannot withdraw.
The decoder converts exp to a readable local timestamp, runs a live countdown while the page is open, and draws a lifetime progress bar from iat to exp so you can see how much of the window has been used. Its validation list flags a token whose exp has passed, a token with no exp, and a token where exp is less than or equal to iat, which usually means a unit or arithmetic mistake at the issuer.
Examples
{
"iat": 1735689600,
"exp": 1735693200
}1735689600 is 2025-01-01 00:00:00 UTC. The difference of 3600 seconds is the whole lifetime.
// Wrong: JavaScript Date.now() returns milliseconds
{ "exp": 1735693200000 }
// Right: seconds
{ "exp": 1735693200 }The wrong version parses as a date roughly fifty thousand years away, so the token never expires.
Things that catch people out
- Writing milliseconds into exp. The value still parses, so nothing errors, and the token simply never expires. Divide by 1000 and floor it.
- Assuming a valid exp means the session is live. Ending a session, revoking consent or deleting the account does not invalidate a token already signed.
- Zero leeway on a verifier whose clock drifts. A few seconds of skew rejects freshly issued tokens intermittently, which is very hard to reproduce.
Try it: JWT Decoder
Paste a token to decode the header and payload, read the claims and expiry, and verify the signature in your browser. Nothing is uploaded.
JWT Decoder
LOCAL · Browser-OnlyDecode and inspect JSON Web Tokens without sending them to a server
Related JWT claims and algorithms
All jwt claims and algorithms →iat (Issued At) Claim in a JWT
The iat claim records when a JWT was created. What it is good for, why it is not an expiry, and the age and lifetime figures the decoder derives.
nbf (Not Before) Claim in a JWT
The nbf claim marks the earliest time a JWT may be accepted. When a not before time is worth setting, and how the decoder flags a future one.
jti (JWT ID) Claim in a JWT
The jti claim gives a JWT a unique identifier. How it supports replay detection and denylists, what it costs to store, and how the decoder shows it.
azp (Authorized Party) Claim in a JWT
The azp claim names the client an ID token was issued to. When OpenID Connect requires it, how it differs from aud, and what the decoder shows.
nonce Claim in an OpenID Connect ID Token
The nonce claim binds an ID token to one authentication request. How the value round trips, why it must be compared, and how the decoder shows it.
auth_time Claim in an OpenID Connect ID Token
The auth_time claim records when the end user actually authenticated, not when the token was issued. How max_age uses it and how the decoder shows it.
Tools for this
- JWT Decoder Free online JWT decoder - decode and inspect JSON Web Tokens without sending them to a server
- Timestamp Converter Free online timestamp converter - convert between Unix timestamps and human-readable dates instantly