
JWT exp, nbf, iat: Expiration & Clock Skew Guide
A technical examination of JWT exp, nbf, and iat claims, focusing on expiration handling, clock skew mitigation, and token lifetime management for backend engineers.
exp, nbf, and iat: Expiration, Clock Skew, and Lifetimes
Part 6 of the JWT From the Spec Up series.
In the architecture of modern backend systems, JSON Web Tokens (JWTs) are often treated as black boxes that magically authenticate users. However, the time-related claims within a JWT—exp (expiration), nbf (not before), and iat (issued at)—are not passive metadata. They are active constraints that enforce temporal validity. For backend engineers, misunderstanding how these claims interact with system clocks leads to two distinct failure modes: accepting compromised tokens past their expiration or rejecting legitimate tokens due to minor clock drift. This article examines the mechanism of time validation in JWTs, focusing on the critical role of clock skew mitigation and leeway.
The Mechanism of Time
A JWT is a signed JSON object. When you decode a token, you see its claims. The time-related claims are defined as numeric values representing the number of seconds since the Unix Epoch (January 1, 1970, 00:00:00 UTC).
Consider a typical access token payload:
{
"sub": "user-123",
"iat": 1678886400,
"exp": 1678890000,
"nbf": 1678886400
}iat: The moment the token was created.exp: The moment the token becomes invalid.nbf: The moment the token becomes valid.
The validation mechanism is straightforward: the server reads its own system clock, converts the current time to a Unix timestamp, and performs numerical comparisons. If the current timestamp T_now satisfies T_now >= nbf and T_now < exp, the token is temporally valid.
This simplicity is deceptive. The assumption here is that the server's clock and the client's clock (or the token issuer's clock) are perfectly synchronized. In distributed systems, they never are.
The Clock Skew Problem
Clock skew refers to the difference in time between two clocks. Even on a single machine, the system clock can drift. In a distributed environment, skew arises from:
- NTP Sync Intervals: Network Time Protocol (NTP) clients synchronize periodically (e.g., every 6–10 minutes). Between syncs, the local clock drifts relative to the reference clock.
- OS Scheduler Jitter: The operating system may delay processing a request, causing the timestamp read at validation time to be slightly later than the actual event time.
- Geographic Latency: While less relevant for static timestamps, if a token is signed by a service in one region and validated in another, network propagation delays can introduce minor discrepancies if clocks are not tightly synchronized.
RFC 7519 acknowledges this reality. It states that implementations MAY use a small amount of leeway when comparing timestamps. Leeway is a buffer, typically measured in seconds, added to the validation window to account for this skew.
How Leeway Works
Leeway is a positive integer representing seconds of tolerance. It is applied asymmetrically depending on the claim:
-
For
exp(Expiration): You apply leeway asexp + leewayfor expiration checks. Effectively, you allow the token to be valid slightly past its expiration time.- Naive Check:
if (now >= exp) reject - Leeway Check:
if (now >= exp + leeway) reject - Result: A token that expired 5 seconds ago is still accepted if leeway is 10 seconds.
- Naive Check:
-
For
nbf(Not Before): You apply leeway asnbf - leewayto allow tokens slightly before their stated not-before time. This accounts for scenarios where the validator's clock is ahead of the issuer's clock.- Naive Check:
if (now < nbf) reject - Leeway Check:
if (now < nbf - leeway) reject - Result: A token issued for future use is accepted if the server's clock is slightly ahead of the issuer's clock.
- Naive Check:
Implementation Strategy
Most JWT libraries handle leeway internally, but understanding the underlying mechanism is crucial for debugging validation errors. Let's look at a concrete scenario.
Scenario: A user logs in from a device in Tokyo. The authentication server is in Frankfurt. The token has an exp of 1678890000. The user's device clock is 3 seconds ahead of the Frankfurt server's clock. The user makes a request exactly at the expiration moment according to the Frankfurt server.
- Frankfurt Server Time: 1678890000
- Tokyo Client Time: 1678890003
- Token
exp: 1678890000
If the Frankfurt server validates the token using its own clock without leeway:
now (1678890000) >= exp (1678890000)→ True.- Result: Token rejected. The user sees an "Unauthorized" error despite having a valid token.
If the Frankfurt server uses a leeway of 5 seconds:
- Effective expiration =
exp + leeway= 1678890005. now (1678890000) < effective_exp (1678890005)→ True.- Result: Token accepted.
However, leeway is a security trade-off. Increasing leeway increases the window during which a stolen token can be used. If your leeway is 60 seconds, a stolen token remains valid for 60 seconds after its intended expiration.
Code Example: Explicit Leeway
Here is how a robust validation function might look in Python using PyJWT, explicitly handling leeway:
import jwt
import time
def validate_token(token, secret, leeway_seconds=10):
try:
# PyJWT automatically applies leeway if provided
payload = jwt.decode(
token,
secret,
algorithms=["HS256"],
options={"require": ["exp", "iat"]},
leeway=leeway_seconds
)
return payload
except jwt.ExpiredSignatureError:
# This exception is raised only if now > exp + leeway
return None
except jwt.InvalidTokenError:
return NoneIn Node.js with jsonwebtoken, the leeway is handled similarly:
const jwt = require('jsonwebtoken');
function validateToken(token, secret) {
const leeway = 10; // seconds
try {
const payload = jwt.verify(token, secret, {
clockTolerance: leeway // This is the leeway parameter
});
return payload;
} catch (err) {
if (err.name === 'TokenExpiredError') {
// Handle specific expiration logic if needed
return null;
}
throw err;
}
}Lifetime Management and iat
While exp and nbf control validity windows, iat (Issued At) serves a different purpose: auditability and rotation detection.
The Role of iat
iat records when the token was created. It does not directly affect validation logic in most libraries, but it is critical for:
- Token Rotation: If you rotate signing keys, you can check
iatto determine which key signed a given token. Old tokens signed with a previous key can be identified and allowed to expire naturally, while new tokens use the new key. - Audit Trails: Logging
iathelps reconstruct user sessions and detect anomalies, such as a token being used immediately after its creation from a geographically distant location.
Recommended Lifetimes
The choice of token lifetime is a balance between security and user experience.
- Short-Lived Access Tokens (5–15 minutes): These should have a tight
expwindow. Since they are used frequently, the risk of leakage is higher. A short lifetime limits the blast radius. Clock skew is less of an issue here because the window is large relative to typical NTP drift (usually <1 second). - Refresh Tokens (Days to Months): These have longer lifetimes but are stored securely (e.g., HttpOnly cookies). They are exchanged for new access tokens. Clock skew is still relevant but less critical because the token is not used directly for API authorization.
When to Use nbf
nbf is rarely used in standard web authentication flows. It is more common in:
- IoT Devices: Where tokens are pre-provisioned and must become valid at a specific time.
- Scheduled Tasks: Where a token should only be usable after a maintenance window ends.
Using nbf introduces complexity because it requires strict clock synchronization between the issuer and the validator. If you don't need this feature, omit nbf to reduce validation overhead and potential for errors.
Conclusion
Implementing JWT expiration correctly is not just about checking a timestamp. It is about managing the uncertainty of time in distributed systems. By understanding the mechanism of exp, nbf, and iat, and by applying leeway judiciously, backend engineers can build systems that are both secure and resilient to clock drift. Remember: leeway is a security trade-off. Keep it small (3–10 seconds) unless you have specific reasons to increase it, and always log validation failures to monitor for unexpected clock skew in your infrastructure.
FAQ
What happens if I set leeway too high? Setting leeway too high (e.g., >60 seconds) significantly increases the window of vulnerability. If an access token is stolen, an attacker can use it for that entire duration after its intended expiration, bypassing your security controls.
Can I use nbf for short-lived access tokens?
It is generally not recommended for standard short-lived access tokens. The complexity of maintaining strict clock synchronization between issuer and validator often outweighs the benefits. nbf is better suited for long-lived refresh tokens or IoT devices with pre-provisioned validity windows.
How do I handle clock skew in a multi-region deployment? Ensure all servers synchronize with a reliable NTP source. If skew persists, consider centralizing token validation or using a consistent time provider across all regions. Monitor skew metrics to determine if a slight increase in leeway is justified, but prefer fixing the root cause (clock drift) over widening the security window.
Does iat affect token validation?
No, iat is not used for validation in most standard JWT libraries. It is primarily for auditing, key rotation detection, and session tracking.
Common Pitfalls
- Ignoring Clock Skew Entirely: Implementing strict
now == expchecks leads to immediate rejection of valid tokens in distributed environments where clock drift is inevitable. - Using Excessively Large Leeway Values: Setting leeway to minutes instead of seconds turns a minor synchronization issue into a major security flaw, allowing stolen tokens to be used for extended periods.
- Misapplying Leeway Direction: Applying leeway incorrectly (e.g., subtracting from
expinstead of adding) can cause tokens to expire prematurely or remain valid indefinitely, breaking the intended security model.
Practical Takeaways
- Leeway is a Security Trade-off: Always keep leeway minimal (3–10 seconds) to balance user experience with security. Larger leeways increase the window for token misuse.
- Apply Leeway Correctly: For
exp, useexp + leeway. Fornbf, usenbf - leeway. This ensures tokens are accepted slightly past expiration or slightly before issuance due to clock drift. - Leverage
iatfor Auditing: Useiatfor key rotation and audit trails, not for validation logic. - Monitor Clock Drift: Regularly check NTP synchronization status across your infrastructure to minimize skew and avoid relying heavily on leeway.
Related posts
JWT sub and aud: Identity and Audience
A technical examination of JWT sub and aud claims, focusing on identity resolution and audience validation for backend and identity engineers.
JWT JTI: Replay Protection and Token Revocation
Learn how the JWT JTI claim enables effective replay protection and token revocation strategies for backend security.
JWT Custom Claims: Public, Private, and Custom | JWT From the Spec Up
Understand the distinctions between public, private, and custom claims in JSON Web Tokens, including IANA registry usage and namespacing best practices.