What Is TOTP?

TOTP stands for Time-based One-Time Password. It is the algorithm that generates the six-digit verification codes you see in authenticator apps like Google Authenticator, Microsoft Authenticator, and Authy. The algorithm is defined in RFC 6238, published by the Internet Engineering Task Force (IETF) in 2011.

TOTP is an extension of HOTP (HMAC-based One-Time Password, defined in RFC 4226). Where HOTP uses an incrementing counter to generate each password, TOTP replaces that counter with a value derived from the current time. This means both the server and the client can independently compute the same code at the same moment without any communication between them, as long as they share a secret key and their clocks are reasonably synchronized.

The TOTP Algorithm Step by Step

Generating a TOTP code involves five operations applied in sequence. Each step is deterministic: given the same inputs, the output is always identical. This is what allows two devices that never communicate to produce the same code at the same time.

Step 1: The Shared Secret

Everything begins with a shared secret — a cryptographic key known to both the server (the service you are logging into) and the client (your authenticator app or device). This secret is typically a random byte sequence, 20 bytes (160 bits) long for SHA-1, or longer for SHA-256 (32 bytes) and SHA-512 (64 bytes).

The secret is encoded in Base32 (defined in RFC 4648) before it is shown to the user. Base32 uses only the uppercase letters A through Z and the digits 2 through 7, which makes it unambiguous to read and type — there is no confusion between the digit 0 and the letter O, or between 1 and l. A typical Base32 secret looks like JBSWY3DPEHPK3PXP.

Before the HMAC computation, the Base32 string is decoded back into its raw binary form. This decoded byte array is the actual cryptographic key.

Step 2: Time Step Calculation

TOTP derives a time counter (called T) from the current Unix timestamp. The formula is:

T = floor(current_unix_time / time_period)

The time_period (also called the time step) is almost always 30 seconds. The current_unix_time is the number of seconds since midnight UTC on January 1, 1970.

For example, if the current Unix time is 1,700,000,000 (November 14, 2023, at 22:13:20 UTC), then T = floor(1700000000 / 30) = 56,666,666. This integer is the same for every moment within that 30-second window, which is why everyone computing a TOTP code during the same window gets the same result.

The counter T is then encoded as an 8-byte big-endian integer. Leading bytes are zero-padded. This 8-byte value becomes the message input to the HMAC function.

Step 3: HMAC Computation

The core cryptographic operation is HMAC — Hash-based Message Authentication Code. TOTP computes:

HMAC-SHA1(secret, T)

Here, secret is the decoded binary key from step 1, and T is the 8-byte time counter from step 2. HMAC-SHA1 combines the key and message through two rounds of SHA-1 hashing with specific padding, producing a 20-byte (160-bit) hash value.

The HMAC construction ensures that only someone who knows the secret key can produce the correct hash for a given time counter. An attacker who sees a TOTP code cannot reverse-engineer the secret from it, because the HMAC output reveals no useful information about its key input.

Step 4: Dynamic Truncation

The 20-byte HMAC output is far too long to use as a short numeric code. TOTP applies a procedure called dynamic truncation to extract a manageable 4-byte (31-bit) integer from it.

The process works as follows:

  1. Take the last byte of the 20-byte HMAC output and extract its low-order 4 bits. This gives a value between 0 and 15, called the offset.
  2. Starting at that offset, read 4 consecutive bytes from the HMAC output.
  3. Mask the most significant bit of the first byte (set it to 0) to ensure the result is a positive 31-bit integer. This avoids ambiguity across programming languages that handle signed integers differently.

The result is a 31-bit unsigned integer — a number between 0 and 2,147,483,647. The term "dynamic" refers to the fact that the offset changes with every HMAC output, so different 4-byte windows of the hash are selected each time.

Step 5: Modular Reduction

Finally, the 31-bit integer is reduced to the desired number of digits using the modulo operation:

code = truncated_value mod 10digits

For a standard 6-digit code, this is:

code = truncated_value mod 1,000,000

The result is a number between 0 and 999,999. It is then left-padded with zeros to exactly six characters — so if the modulo result is 7,392, the displayed code is 007392.

This is the code you type into the login form. The server performs the exact same five steps and compares the results. If they match, you are authenticated.

Why Codes Change Every 30 Seconds

The 30-second period is the defining feature of TOTP. Every 30 seconds, the time counter T increments by one, which changes the HMAC input, which produces an entirely different hash, which yields a completely different code. There is no mathematical relationship between consecutive codes that an observer could exploit.

The 30-second period is a deliberate balance. A shorter period would give an attacker less time to use a stolen code but would frustrate users who cannot type fast enough. A longer period would be more convenient but would extend the window in which an intercepted code remains valid.

To accommodate clock drift — small differences between the server's clock and the client's clock — most servers accept not just the current code but also the code for the previous and next time steps. This gives an effective validity window of roughly 90 seconds (the current 30-second window plus one window on each side). Some implementations widen this further, accepting codes up to two or three steps away, especially during initial setup.

The Role of the Shared Secret

The shared secret is the single piece of information that makes the entire system work. It is created by the server when you enable two-factor authentication on your account and is transferred to your authenticator exactly once, through one of two methods:

  • QR code: The server displays a QR code that encodes a URI in the format otpauth://totp/Label?secret=BASE32SECRET&issuer=ServiceName. Your authenticator app scans this and extracts the secret, issuer, algorithm, digit count, and period.
  • Manual entry: The server displays the Base32-encoded secret as a text string that you type into your authenticator by hand.

After this initial exchange, the secret is never transmitted again. Both sides store it independently and use it to compute codes. This is what makes TOTP fundamentally different from SMS-based 2FA, where a code must be sent over a communication channel each time.

The secrecy of this key is critical. Anyone who obtains the shared secret can generate valid TOTP codes for your account indefinitely. This is why authenticator apps must be protected — a compromised device means compromised secrets. It is also why backup codes and recovery methods exist: if you lose access to the secret, there is no way to reconstruct it from past codes.

Supported Algorithms

RFC 6238 specifies three HMAC algorithms for TOTP:

  • HMAC-SHA1 — The default. It produces a 20-byte hash. This is what Google Authenticator and the vast majority of services use. Despite theoretical weaknesses in raw SHA-1 for collision resistance, HMAC-SHA1 remains cryptographically secure for the message authentication purpose that TOTP requires. No practical attack against HMAC-SHA1 in the TOTP context has been demonstrated.
  • HMAC-SHA256 — Produces a 32-byte hash. Provides a larger security margin and is used by some services that want to future-proof their 2FA implementation. The truncation procedure works the same way, with the offset extracted from the last byte and 4 bytes read from the resulting position.
  • HMAC-SHA512 — Produces a 64-byte hash. Offers the widest security margin. Used rarely, primarily in high-security environments or by services that want maximum cryptographic headroom.

Compatibility note: Not all authenticator apps support SHA-256 and SHA-512. Google Authenticator, for instance, historically supported only SHA-1 (though newer versions have added SHA-256 support). If you configure an account to use SHA-256 or SHA-512, make sure your authenticator actually supports the algorithm — otherwise it will silently generate wrong codes using SHA-1.

Security Properties

TOTP provides several concrete security guarantees, along with some limitations worth understanding:

  • One-time use: A well-implemented server accepts each code only once within its validity window. If you use a code to log in, the server marks it as consumed and rejects it if presented again. This prevents replay attacks where someone intercepts and reuses your code.
  • Time-limited validity: Each code is valid for at most one time period (typically 30 seconds), plus whatever clock-drift tolerance the server allows. An intercepted code becomes useless within a minute or less.
  • Brute-force resistance: A 6-digit code has one million possible values. An attacker guessing randomly has a 0.0001% chance of success per attempt. Servers implement rate limiting and account lockout to make brute-force impractical.
  • No forward secrecy: This is a limitation. If an attacker obtains the shared secret, they can generate valid codes for all future time periods and can also compute codes for past time periods. The system relies entirely on the secrecy of the shared key. There is no mechanism analogous to forward secrecy in TLS, where past session keys are irrecoverable even if a long-term key is compromised.
  • Phishing vulnerability: TOTP does not protect against real-time phishing. If an attacker operates a fake login page that captures your password and TOTP code simultaneously, they can relay both to the real server before the code expires. This is why security-critical environments are moving toward phishing-resistant methods like FIDO2/WebAuthn hardware keys.

TOTP vs. HOTP

TOTP and HOTP share the same cryptographic core — HMAC followed by dynamic truncation and modular reduction. They differ in what drives the counter:

  • HOTP (HMAC-based One-Time Password, RFC 4226) uses a monotonically incrementing counter. Each time you generate a code, the counter advances by one. The server tracks the counter value it expects and advances its own counter when a valid code is received. If the client counter gets ahead (because you generated codes without using them), the server performs a look-ahead search within a configurable window.
  • TOTP (RFC 6238) replaces the counter with floor(unix_time / period). No counter state needs to be synchronized. Both parties derive the counter independently from their clocks.

The practical consequence is that HOTP codes remain valid until they are used (or the counter is advanced), while TOTP codes expire automatically after their time period. This makes TOTP preferable for most use cases: a stolen HOTP code remains dangerous indefinitely, whereas a stolen TOTP code becomes worthless within seconds.

HOTP still appears in hardware tokens (like some YubiKey configurations) and in environments where clock synchronization is impractical.

Standards and RFCs

TOTP is built on a stack of three IETF standards:

These RFCs are freely available and form the complete technical specification for any TOTP implementation.

See It in Action

Now that you understand how TOTP works under the hood, try generating a code yourself. Enter a Base32 secret key and watch the algorithm produce a live verification code.

Open the 2FA Generator