How TOTP Codes Work
A TOTP code is a 6-digit number that an authenticator app and a server each compute independently, from the same two inputs: a shared secret key and the current time, divided into 30-second windows. The code itself is never transmitted during setup and carries no information about the secret, yet both sides arrive at the same digits — because TOTP is not magic or randomness, it is one published algorithm (RFC 6238) applied to the same inputs. This article walks the calculation end to end, explains why a "wrong code" is almost always a clock problem, and covers the handling rules that decide whether your second factor stays a second factor. You can run every step yourself in the TOTP Generator, which computes codes locally in your browser.
Two inputs, one code: the secret and the clock
When you turn on two-factor authentication, the service generates a random secret — typically 20 bytes, shown to you as a string of Base32 characters and, as a convenience, encoded into a QR code. That secret is stored in exactly two places: the service’s database and your authenticator. From that moment on, logging in is a synchronised computation. Both sides take the current Unix time, divide it by the time step (30 seconds for almost every service), and feed the resulting counter, together with the secret, into a hash function. Whoever presents the matching output is treated as holding the secret.
The elegance of the design is what it leaves out. There is no challenge to send, no code to deliver, no network round trip, and nothing per-login for an attacker to intercept: the "one-time" property comes from the clock, because the counter changes every 30 seconds and old outputs become worthless. It also means the system has exactly two things that can go wrong — the secret, and the time. Nearly every TOTP failure, and every TOTP theft, traces back to one of those two.
The calculation, step by step
The counter is first written as an 8-byte big-endian integer — a fixed-width encoding both sides agree on. That message is then run through HMAC with the secret as the key, using the agreed hash: SHA-1 by default, with SHA-256 and SHA-512 defined for services that choose them. HMAC is a keyed construction, not a plain hash: simply hashing the counter would let anyone with the algorithm reproduce codes, whereas HMAC outputs are unforgeable without the secret and cannot be run backwards to recover it.
A digest is 20 bytes or more; a login box wants 6 digits. The bridge is dynamic truncation: the last half-byte of the digest selects an offset, four bytes are read from that offset with the top bit masked off (to avoid sign ambiguity), and the resulting 31-bit number is reduced modulo 10^digits — a million for the standard six digits, zero-padded on the left. That is the code you type. The next window recomputes from scratch; there is no chain linking one code to the next, which is why a photographed code is worthless thirty seconds later.
When the code is rejected: it is usually the clock
Because the counter is derived from time, generator and server must agree on which 30-second window it currently is. Most servers soften this by accepting the neighbouring windows too — one step either side — which quietly absorbs small skew. Beyond that, every code is wrong, no matter how correct the secret is, and the failure looks identical to a mistyped digit: a flat rejection with no hint about which input disagreed.
So the first diagnostic for a suddenly-failing authenticator is never the secret; it is the clock on the device generating the codes. A manually-set time, a dying CMOS battery, a phone that spent a flight in the wrong timezone mode — any of these can push the device a minute or more adrift. Our TOTP Generator shows a live clock card and measures your device against server time for exactly this reason. Turn on automatic date and time, and the codes almost always start working again — no reset, no new secret, no support ticket.
The secret is the whole game
Strip the ceremony away and TOTP security is one fact: anyone who has the secret has the second factor, forever, from anywhere, with no way for the service to tell their codes from yours. The QR code you scan at setup is not a picture of a code — it is the secret itself, plus the account label and parameters, formatted as an otpauth:// URI. A screenshot of it is a permanent copy of your second factor.
That is why the handling rules are stricter than for passwords. A password is verified by the server and can be stored hashed; a TOTP secret must be recoverable in raw form by both sides, so it cannot be hashed away, and every copy is a live copy. Keep the master copy in your authenticator or an encrypted password manager. Never type it into a website that generates codes on its server — you have handed a stranger a permanent key — and never paste it into a chat, as the next section explains.
Why the secret must never go in a chat box
Pasting a 2FA secret into a chat — a support conversation, a team channel, an AI assistant — feels harmless because the string looks like gibberish and the conversation feels private. It is neither. Chats are logged, retained, synced to every device on the account, searchable, and processed on servers you do not control; AI chats add training pipelines and long retention to that list. The moment the secret lands there, your second factor exists in systems designed to keep and index text.
The safe pattern is that the secret should only ever exist in three kinds of places: the service’s database, your authenticator or password manager, and local computation on a device you control — which is how the TOTP Generator on this site is built, with the secret held in page memory only and destroyed on refresh. If a secret has already been pasted somewhere it should not be, treat it as burned: turn two-factor off and back on at the service to mint a fresh one, re-enrol your authenticator, and while you are there, check the password itself in the Password Breach Check.
What TOTP does not stop
TOTP defeats password theft, credential stuffing and database leaks: knowing your password is no longer enough. It does not defeat real-time phishing. A fake login page that relays your credentials to the real service and asks for the code can pass the code along within its 30-second window — the code proves possession of the secret, not that you are talking to the genuine site. Session-cookie theft bypasses it just as completely, because the code is only checked once.
This is why passkeys and hardware security keys are displacing TOTP at the top end: they bind the proof to the site’s origin, leaving nothing typeable for a relay to steal. TOTP remains a strong, universal baseline — vastly better than SMS codes, which inherit the phone network’s weaknesses — but it should be deployed with open eyes: protect the secret like a master key, keep backup codes somewhere separate, keep your clock honest, and prefer a passkey wherever the service offers one.