Clock skew
Which checks depend on the clock, the tolerances each one allows, how to recognise a skewed clock, and how to fix it.
On this page
Symptom#
Things fail even though the credentials are right, and the failure is about time:
- A DPoP proof is refused with the DPoP proof iat is outside the 60-second window.
- A client assertion fails with
invalid_client. - A new access token is refused by your API as not yet valid, or a recently issued token looks expired.
- An authenticator app code is always wrong, although you type it correctly.
Likely causes#
Several checks compare a time in a token or proof with the clock of whoever checks it. If the two clocks differ by more than the tolerance, the check fails.
| Check | Who compares | Tolerance |
|---|---|---|
DPoP proof iat | Identity, and your API when it verifies proofs | 60 seconds either side at most; identity may allow less |
DPoP proof jti | Identity | Remembered for 5 minutes (may be set shorter, never under twice the iat window) |
Client assertion exp | Identity | The assertion can run at most 5 minutes ahead of the server's time (the platform can lower that), and it has to be unexpired |
Access token nbf, iat, exp | Your API | Whatever your verifier allows; the SDK allows 5 seconds. A token is valid from the moment it is issued, and no longer than 900 seconds. A verifier whose clock is behind sees a new token as not valid yet. |
| Authenticator app code | Identity | One 30-second step either side |
| Emailed link and code, session and token lifetimes | Identity | The server's clock decides. Your device's clock does not change these. |
| Back-channel logout token | Identity, when sending | A token very close to its expiry is treated as expired and is not sent |
Typical reasons for a wrong clock: a virtual machine that was suspended or restored, a container host without time synchronisation, a laptop with the time set by hand, a phone with automatic time turned off, or a time zone chosen to dodge a prompt. Time zones themselves do not matter, since the checks use seconds since the epoch.
What to check#
- Read the
Dateheader of a response from identity and compare it with your own clock at the same moment. A gap of more than a few seconds on a machine that signs proofs is the problem. - On a server, check that a time service is running and synchronised. On Linux,
timedatectlshows whether the clock is synchronised. - For a phone and an authenticator app, check that the phone sets its time automatically.
- Check that your API verifies tokens using the same time source as the rest of your hosts.
Fix#
- Synchronise the clock with a network time service on every host that signs proofs or assertions, and on every host that verifies tokens. This is the real fix.
- Do not widen tolerances to cover for a bad clock. In particular, do not accept proofs outside the 60-second window in your own verifier.
- Do not set
iatin the future to compensate. Both directions are checked. - Build a fresh proof for every request, including a retry, so a delay does not push an old proof out of the window.
- For an authenticator app, correct the phone's time, then wait for the next code. If you are locked out, choose Use a recovery code where your organization allows it.
- For a short delay on a verifier, allow a small leeway on
nbfin your token library, a few seconds at most.