ASVS 5.0 V10.4.3 (Level 1) requires that an authorization code expires quickly. The ceiling is 10 minutes for L1 and L2 applications and 1 minute for L3 applications.
Those are maximums. A normal client redeems the code within a second or two of the redirect, so 30 to 60 seconds is a sensible default for everyone.
Why it matters
A code is a bearer credential for a short window. The shorter that window, the less time a leaked code is worth anything. Combined with single use (V10.4.2) and PKCE (V10.4.6), a short lifetime makes interception attacks very hard to profit from.
How to implement it
Set the expiry when you create the code, and check it on redemption using the server clock, never a timestamp from the client.
import hashlib
import secrets
from datetime import datetime, timedelta, timezone
CODE_TTL = timedelta(seconds=60)
def issue_code(store, grant_id):
code = secrets.token_urlsafe(32)
store.save(
code_hash=hashlib.sha256(code.encode()).hexdigest(),
grant_id=grant_id,
expires_at=datetime.now(timezone.utc) + CODE_TTL,
)
return code
In Keycloak the setting is the client's Advanced tab, OAuth 2.0 code lifespan. In Spring Authorization Server it is part of the token settings. In hosted identity providers it is often fixed, so check the documentation and note the value as evidence.
How to test it
Start a flow, copy the code, and wait past your configured lifetime. Send the token request. You should get invalid_grant. Repeat just inside the limit to prove the happy path still works. For L3, test at 61 seconds.
Clock and storage details
Compare the expiry against the server's clock in UTC, and keep servers synchronized. If your codes live in a cache with a time to live, set the cache expiry to the same value as the code lifetime, so expired codes disappear even if a cleanup job stops. Still check the timestamp when redeeming, because cache eviction is not a security control on its own.
Common mistakes
- Setting an hour because a slow mobile client once timed out. Fix the client instead.
- Checking expiry only on issue, never on redemption.
- Trusting clock values that drift between servers. Keep NTP healthy.
Quick check
What is the maximum code lifetime for an L3 application?
One minute. L1 and L2 may go up to 10 minutes.