TL;DR
When your system relies on token expiry for authorization but doesn’t have a reliable clock (e.g., distributed systems, mobile apps), use a sliding window approach combined with token refresh mechanisms and consider using monotonic clocks where possible. This prevents issues caused by time differences between servers or devices.
Understanding the Problem
Token expiry is a common security practice. However, if your system’s clocks aren’t perfectly synchronized, tokens can expire prematurely (false negatives) or remain valid longer than intended (security risk). This is especially problematic in:
- Distributed Systems: Different servers have different clock times.
- Mobile Apps: User devices’ clocks are often inaccurate and easily changed.
Relying on Network Time Protocol (NTP) alone isn’t always enough for strict security requirements due to potential drift.
Solution Steps
- Sliding Window Approach: Instead of checking if a token is expired based on a fixed time, allow a small grace period.
- Example: If a token has a lifetime of 1 hour, accept tokens that are slightly older than 1 hour (e.g., up to 5 minutes old) and slightly newer. This accounts for minor clock discrepancies.
- When a user authenticates, issue both an access token (short lifetime) and a refresh token (longer lifetime).
- The client uses the refresh token to obtain new access tokens without re-entering credentials.
- This limits the impact of clock drift because access tokens are frequently renewed.
- A monotonic clock only moves forward, even if the system clock is adjusted backwards. This avoids issues with time going back in time.
- Example (Python):
import time monotonic_time = time.monotonic()
- This shifts the responsibility of accurate timekeeping to a single point.
- When validating, compare the current time (with sliding window) against the stored timestamp.
- Log discrepancies and alert administrators if clocks are significantly out of sync.
Code Example (Simplified Token Validation)
This is a very basic example in Python, demonstrating the sliding window concept.
import time
def validate_token(token, expiry_timestamp, grace_period=300): # Grace period in seconds
current_time = int(time.time())
if current_time <= expiry_timestamp + grace_period:
return True
else:
return False
# Example Usage
token_expiry = int(time.time()) + 3600 # Token expires in 1 hour
if validate_token("my_token", token_expiry):
print("Token is valid")
else:
print("Token has expired")
Important Considerations
- Grace Period Size: Choose a grace period that balances security and usability. A larger grace period increases the risk of allowing stale tokens but reduces false negatives.
- Refresh Token Security: Protect refresh tokens carefully, as they have longer lifetimes. Store them securely (e.g., encrypted database) and consider rotating them regularly.
- Token Revocation: Implement a mechanism to revoke tokens if necessary (e.g., user logs out).