Skip to content
TDACorpIDENTITYSign in

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.

CheckWho comparesTolerance
DPoP proof iatIdentity, and your API when it verifies proofs60 seconds either side at most; identity may allow less
DPoP proof jtiIdentityRemembered for 5 minutes (may be set shorter, never under twice the iat window)
Client assertion expIdentityThe 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, expYour APIWhatever 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 codeIdentityOne 30-second step either side
Emailed link and code, session and token lifetimesIdentityThe server's clock decides. Your device's clock does not change these.
Back-channel logout tokenIdentity, when sendingA 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#

  1. Read the Date header 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.
  2. On a server, check that a time service is running and synchronised. On Linux, timedatectl shows whether the clock is synchronised.
  3. For a phone and an authenticator app, check that the phone sets its time automatically.
  4. 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 iat in 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 nbf in your token library, a few seconds at most.

Verified against commit 70b6781