Usually feels like
Seconds
It finishes while you are still looking at the screen.
It belongs in seconds because a code lives for a short fixed span, and the longest you can ever wait for the next one is a single span.
The wait, in plain words
A code that changes on its own has a life. Most of the time you catch it near the start of that life and none of this matters. Sometimes you look down and it is about to turn over.
The instinct is to type faster. The better move is to let it go and use the next one. A code that expires between your typing it and the market checking it is refused in exactly the way a wrong code is refused, and the screen will not tell the two apart for you.
So this wait is self imposed, short, and bounded at the top. You know the ceiling before you start: no more than the life of a single code, and usually a good deal less.
Underneath, while nothing moves
The code is not sent to you. Both ends compute it from the same shared secret and from the current time, and they agree because their clocks agree. Nothing travels, which is why a code still works on a device with no connection at all.
That construction has a consequence people find surprising. A code can be right and still be refused, because rightness here is relative to a clock. If the clock on your device has drifted, your app is producing the code for a moment that has already passed or has not yet arrived.
| What you see | What it usually points at |
|---|---|
| Refused once, then accepted with a fresh code | The first code ran out in flight. Nothing is wrong. |
| Refused every time, with codes typed early in their life | The clock on the device making the codes has drifted away from real time. |
| Accepted only when you type the code late in its life | That device is running behind, so its codes arrive early. |
| Accepted only when you type it the instant it appears | That device is running ahead, so its codes are stale by the time they are checked. |
In the drifted cases the fix is not on the market's side and not in the code. It is the clock on the machine or the phone producing the codes. Set it to synchronise with real time and the refusals stop.
Systems of this shape generally accept a code from just before or just after the current moment, to absorb small drift and the time it takes to type. That tolerance is narrow by design, and it is exactly what you are leaning on when you grab a code at the end of its life.
Behaving, and not behaving
Because you choose this wait, the question is not whether it is behaving. It is whether you are reading the timer honestly.
A code used at the right moment
You start typing on a code that has just appeared, and the sign in screen takes it without comment.
If you use a fresh code every time and are never refused, both clocks agree and none of this needs your attention again.
A code used at the wrong moment
You start typing on a code that is nearly finished, and the screen tells you it was wrong. The code was not wrong. It was late.
Refusals of this kind push you towards a cooldown, and the cause looks like a forgotten passphrase when it is really a clock.
The tell is the pattern. Occasional refusals scattered among successes point at timing. Constant refusals with codes you know are correct point at drift.
Neither is a reason to try faster. A refused code costs an attempt, and attempts are the thing this screen counts. See a cooldown after failed tries for what happens when the count climbs.
Safe to do meanwhile
The span is short enough that the only sensible thing to do with it is prepare the rest of the step.
- Let the current code dieA code near the end of its life is a failed attempt waiting to happen.
- Check the clock on the device making codesAutomatic time synchronisation removes this entire class of problem.
- Fill in everything else firstHave the rest of the form complete so the fresh code is typed and sent in one motion.
- Find out whether the field wants spacesSome boxes accept grouped digits and some do not, and learning that afterwards costs an attempt.
- See the rest of the bandEvery wait that finishes while you are still watching.
What makes it longer
There is a hard ceiling on one span, so what varies is how many spans you end up spending rather than how long any of them lasts.
- A drifted clock, which turns a bounded wait into a run of refusals with no obvious cause.
- Typing on a code that is nearly over, which costs an attempt and then a fresh span anyway.
- A slow path, which eats the tolerance between your typing and the market checking.
- A screen that also wants a challenge picture, which adds its own wait before the code can go anywhere. See the captcha picture appearing.
- Reading the code off a device you have to unlock first, which spends part of the span on a lock screen.
- Counted failures, which can lift the whole business into the next band up.
What this card is not. This is not about setting up a second factor, only about the moment of using one.