Skip to main content
Technology

How TOTP Works - The 6-Digit Code Generated From Time Sync

What TOTP Is - One-Time Codes That Change Every 30 Seconds

Time-based One-Time Password (TOTP) is the algorithm behind Google Authenticator, Authy, Microsoft Authenticator, and 1Password. The server and the user's device share a secret key, and both compute a 6-digit number by combining that key with the current time. The number changes every 30 seconds, and successful login requires the user to type whatever digits are valid in the current window. RFC 6238 standardized this in 2011, ensuring vendor-neutral interoperability.

TOTP's biggest practical advantage is that it works without any network connectivity once the secret is shared. The server does not need to send anything to the device, and the device does not need to query the server. This makes TOTP cheaper to operate at scale than SMS-based one-time passwords, while sidestepping the SIM-swapping attacks that plague SMS authentication.

HOTP - The Counter-Based Predecessor

TOTP is built on top of HMAC-based One-Time Password (HOTP), defined in RFC 4226. HOTP uses a counter and a secret key, hashing them with HMAC-SHA-1 and extracting a 6-digit number from the result. Each successful login increments the counter on both sides, so the next code is different. HOTP works without any time source, which makes it suitable for offline hardware tokens with no clock.

The downside of HOTP is counter desynchronization. If a user opens the authenticator app multiple times without using the codes, the device's counter advances while the server's stays put. The server must therefore look ahead a few values to find a match, which adds operational complexity. TOTP solves this elegantly by replacing the counter with the current time divided into 30-second buckets.

The TOTP Algorithm - 30-Second Time Steps

TOTP computes the counter as the current Unix timestamp divided by 30 (integer division). For example, at Unix time 1716000000 (May 18, 2024 at 14:40 UTC), the counter is 57200000. That counter is fed into the HOTP algorithm with the shared secret, producing a 6-digit number. Thirty seconds later, the counter becomes 57200001 and a completely different number is generated.

The 30-second step size from RFC 6238 balances usability and security. Too short and users cannot type the code in time; too long and brute-force attempts have a wider window to succeed. Servers commonly accept the previous and next 30-second windows as well, giving roughly 90 seconds of total tolerance. Different services tune this slightly: Steam Guard uses a 30-second step but with custom tweaks, while some enterprise tokens use 60 seconds.

The Secret Inside the QR Code - The otpauth URI

When you enable two-factor authentication, the QR code on screen encodes an otpauth:// URI containing the shared secret. A typical URI looks like otpauth://totp/Example:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=Example. The secret is Base32-encoded (Base32 is used because it avoids characters that look alike in display fonts). Authenticator apps parse this URI and store the secret locally.

Anyone who photographs the QR code can clone the OTP generator, so the setup screen should be displayed only once and never during a screen-sharing session. Most services pair TOTP setup with a set of one-time backup codes. Each backup code is a single-use long random string that bypasses TOTP, useful when a phone is lost. Storing backup codes in a separate password manager or printed in a safe place is the standard practice.

Time Drift - The Most Common Cause of Failure

When TOTP authentication fails, the cause is usually that the server and device disagree on the current time. Servers typically synchronize to UTC via NTP, but a phone with manually adjusted time, or one that just returned from international travel with confused settings, can drift by a minute or more. Google Authenticator includes a "Time correction" feature that fetches the correct time from Google and offsets internal calculations accordingly.

Server-side time drift is just as risky. Containers running without proper NTP sync can drift tens of seconds, especially in nested virtualization. Industry case studies repeatedly describe outages where every user is locked out because the authentication server's clock fell behind by minutes. For systems implementing TOTP, regular NTP sync and alerting on time-sync failures are non-negotiable operational requirements.

Implementation Notes - SHA-1 to SHA-256, Replay Protection

TOTP defaults to HMAC-SHA-1, which RFC 6238 considers adequate for OTP use cases. Newer implementations may select SHA-256 or SHA-512 via the algorithm parameter in the otpauth URI. Older versions of Google Authenticator did not support SHA-256, so backward compatibility is the main reason most services still use SHA-1. For greenfield implementations targeting modern authenticator apps only, SHA-256 is a reasonable upgrade.

Servers must also prevent replay attacks. If two login attempts arrive within the same 30-second window, only the first should succeed; otherwise, an attacker who captured a code could reuse it. Storing the most recent successfully used counter value per user and rejecting any equal or smaller value is the canonical defense. The default 6-digit length can be increased to 7 or 8 digits via the digits parameter for higher entropy, at the cost of slightly less convenient input.

XB!LINE

Was this article helpful?

Related Articles