A TOTP code is a function of one secret and one number: the current time divided by 30. Get the secret right and the time wrong, and the six digits are valid for a moment that isn’t now.
Confirm it in thirty seconds
Open the generator and compare your device clock against one you trust: a phone on cellular time, or time.is. More than about half a minute apart and you have your answer.
Try this firstMost servers accept one step either side of now, so a slightly fast clock is often rescued by the neighbouring code. Then fix the clock.
How much drift is too much
The counter is floor(unix_time / 30). Every 30 seconds it advances and the previous code dies. Servers typically accept the step before and after, about a minute of slack in total. Past that the code is refused, and the error always reads “invalid code”, never “wrong clock”.
Fix the clock
- Windows. Settings → Time & language → Date & time → Sync now. Turn on “Set time automatically”.
- macOS. System Settings → General → Date & Time → “Set time and date automatically”.
- Android. Settings → System → Date & time → “Set time automatically”.
- iOS. Settings → General → Date & Time → “Set Automatically”.
- Linux.
timedatectl set-ntp true, then timedatectl status to confirm NTP is active. - Virtual machines. A suspended or migrated VM wakes with a stale clock. Resync inside the guest after every resume; the host clock does not propagate.
Time zone is not the problem
TOTP runs on Unix time, identical in every zone. A machine set to the wrong region shows the wrong wall-clock time and still produces valid codes. Only the absolute time matters.
When the clock really is fine
Four remaining causes, most common first:
- Wrong parameters. SHA-1, 30 seconds and 6 digits is only a default. Kraken issues SHA-512; some enterprise systems issue 8 digits or a 60-second step.
- Truncated secret. A Base32 key copied from a cramped modal is often missing its tail. Re-reveal the key and copy the whole string.
- Non-standard scheme. Steam produces five characters from a 26-symbol alphabet. Authy’s own tokens are 7 digits on a 10-second step. Neither validates against a default TOTP generator.
- Code already used. Banks and some exchanges refuse a code that was already presented, even inside its window. Wait for the next step.
Questions
- How far can my clock drift before 2FA codes fail?
- Roughly 30 to 90 seconds. Most servers accept the 30-second step either side of the current one, so about a minute of drift is tolerated and anything beyond that is refused.
- My phone app works but the browser tool fails.
- Two different clocks. The phone syncs over cellular; the desktop may not be syncing at all. Compare them directly.
- Can I just widen the server’s tolerance?
- If you run the server, yes, but do not. A wider window means a stolen code stays usable for longer, which is the property TOTP exists to remove. Fix the client clock instead.
Related