2fa-authenticationCOMP

TOTP vs HOTP: How One-Time Passwords Really Work (and Which Your 2FA Uses)

TOTP vs HOTP explained: both are HMAC-based OATH one-time-password standards, but TOTP uses time (RFC 6238) and HOTP uses a counter (RFC 4226). Comparison table, which your authenticator app actually uses, and which is more secure.

By Eric Gerard · Editor · PwdFortress5 min readPhoto: Towfiqu barbhuiya — Unsplash

If you have ever wondered what those rotating 6-digit codes in your authenticator app actually are — and why a few hardware tokens behave differently — the answer comes down to two closely related standards: TOTP and HOTP.

New to two-factor in general? Start with what 2FA is and how it protects your accounts.

Short answer

TOTP is time-based: the code is derived from the current time and rotates (and expires) every 30 seconds. HOTP is counter-based: the code is derived from a counter that increments each time a code is used, and it stays valid until it is used. Both are OATH/IETF standards built on HMAC. Your authenticator app almost certainly uses TOTP — that is what Google Authenticator, Authy, Aegis, Bitwarden Authenticator and most websites implement. HOTP shows up mainly on certain hardware tokens.

HOTP: counter-based (RFC 4226)

HOTP — HMAC-based One-Time Password — is the original OATH algorithm, defined in RFC 4226 (2005). Each code is computed from two inputs:

  • A shared secret (a seed provisioned once, usually via a QR code)
  • A counter that starts at zero and increments by one every time a code is consumed

The device runs HMAC-SHA1 (the default) over the secret and the counter, then truncates the result down to a short numeric code — 6 digits by default, optionally 8.

The defining property of HOTP is that the code has no expiry. It stays valid until it is actually used; the counter only moves forward when a code is accepted. That is convenient when there is no reliable clock, but it has a well-known failure mode: desynchronization. If codes are generated on the client without being submitted (someone keeps pressing the button on a token), the client counter runs ahead of the server counter and the two stop matching. To recover, servers implement a look-ahead window — they test the next several counter values, and if one of them matches, they advance their counter to resynchronize.

TOTP: time-based (RFC 6238)

An open padlock resting on a laptop keyboard under red and green lighting
An open padlock resting on a laptop keyboard under red and green lighting

TOTP — Time-based One-Time Password — is defined in RFC 6238 (2011), and it is best understood as a special case of HOTP. Instead of an event counter, TOTP uses the current time divided by a time step (the default step is 30 seconds) as the counter. Plug that time-derived counter into the same HMAC construction and you get a code that automatically changes every 30 seconds and expires when the window rolls over.

Because the counter is the clock rather than your actions, TOTP never desynchronizes from unused codes — there is no "I pressed the button too many times" problem. The trade-off is that it requires the client and server clocks to be roughly synchronized. Servers absorb minor drift with a small tolerance window, typically accepting the previous and next time step in addition to the current one.

Everything else mirrors HOTP: HMAC-SHA1 by default (SHA-256 or SHA-512 are also allowed), 6 digits by default (8 optionally), and the secret provisioned through an otpauth:// URI inside a QR code. If you want to compare the apps that generate these codes, see our best authenticator apps comparison.

Comparison table

PropertyHOTP (RFC 4226)TOTP (RFC 6238)
Moving factorCounter (event-based)Time (current time / step)
Code expires?No — valid until usedYes — every ~30 seconds
Default time stepN/A30 seconds
Main failure modeCounter desync (look-ahead resync)Clock drift (tolerance window)
AlgorithmHMAC-SHA1 (SHA-256/512 optional)HMAC-SHA1 (SHA-256/512 optional)
Digits6 default (8 optional)6 default (8 optional)
Needs network?NoNo
Typical useSome hardware tokens, offline/no-clockAuthenticator apps, most websites

Which your 2FA uses

In practice you rarely choose — the service decides. And the service almost always picks TOTP. The rotating 6-digit code in Google Authenticator, Authy, Aegis, Bitwarden Authenticator or Microsoft Authenticator is TOTP. So is the code on virtually every "scan this QR code" 2FA setup screen you encounter on the web.

HOTP is the exception. You will mostly meet it on hardware tokens — for example a YubiKey can be configured for OATH-HOTP — or in environments where reliable time synchronization cannot be guaranteed, which is exactly the scenario where a counter beats a clock. A YubiKey can actually do several of these: OATH-TOTP, OATH-HOTP, and the much stronger FIDO2. If you want the full picture, see our YubiKey and FIDO2 complete guide.

Security: which is safer

TOTP is generally preferred for one concrete reason: its codes expire. A TOTP code captured by an attacker is only useful for the seconds until the window rolls over, which keeps the interception-and-replay window short. An HOTP code, by contrast, stays valid until it is used, so an intercepted-but-unused HOTP code gives an attacker a longer replay window.

But neither algorithm is a silver bullet. Both TOTP and HOTP are phishable. If a fake login page tricks you into typing a live code, an attacker can relay that code to the real service in real time before it expires. The expiry on TOTP shortens that window but does not close it. This is the structural limitation of all shared-secret OTP schemes.

The only widely deployed factors that are genuinely phishing-resistant are FIDO2 and passkeys, because they bind the authentication to the real site's origin so a relayed credential simply does not work on the attacker's domain. If you want to move up the security ladder, read what a passkey is.

Bottom line

TOTP and HOTP are the same HMAC machinery with a different moving factor: HOTP counts events, TOTP counts time. HOTP's codes never expire but its counter can drift out of sync; TOTP's codes expire every 30 seconds but its clock has to stay roughly aligned. The wider world settled on TOTP for app-based 2FA because expiring codes are the safer default, and HOTP survives mostly on hardware tokens and offline scenarios. Whichever one a service hands you, remember the shared limitation: both can be phished. For accounts that matter most, a phishing-resistant FIDO2 key or passkey is the stronger layer.

For plain-language definitions of TOTP, HOTP, 2FA, passkey and hardware key, see the PwdFortress authentication glossary.


PwdFortress explains authentication standards based on the published RFCs and public documentation. We do not invent test results or statistics.

Frequently asked questions

What is the difference between TOTP and HOTP?

Both are OATH/IETF one-time-password standards built on HMAC. **HOTP** (RFC 4226) derives each code from a shared secret plus a **counter** that increments every time a code is used — the code stays valid until it is used, with no time limit. **TOTP** (RFC 6238) is HOTP where the counter is the **current time divided by a time step** (30 seconds by default), so the code rotates and expires every 30 seconds. In short: HOTP = event/counter-based, TOTP = time-based.

Which one does my authenticator app use, TOTP or HOTP?

Almost certainly **TOTP**. Google Authenticator, Authy, Aegis, Bitwarden Authenticator, Microsoft Authenticator and the vast majority of websites use TOTP — the 6-digit code that changes every 30 seconds. HOTP is much rarer; you mainly see it on some hardware tokens (for example a YubiKey configured for OATH-HOTP) or in setups where reliable time synchronization is not available.

Is TOTP or HOTP more secure?

TOTP is generally preferred because its codes **expire after ~30 seconds**, shrinking the window in which an intercepted code can be replayed. HOTP codes stay valid until used, so an intercepted-but-unused code has a longer replay window. That said, **both are phishable** — an attacker can trick you into entering a live code on a fake site and relay it in real time. Only FIDO2/passkeys are phishing-resistant.

Why does HOTP get out of sync?

HOTP relies on a counter that the client and server each increment. If you generate codes on the client without ever submitting them (for example by repeatedly pressing the button on a hardware token), the client counter moves ahead of the server counter and the codes stop matching. To recover, servers use a **look-ahead window**: they try the next several counter values, and if one matches they resynchronize. TOTP avoids this because the counter is the clock, not your actions.

Does TOTP need an internet connection?

No. A TOTP code is computed locally from the shared secret and the current time, so generation works fully offline. It does, however, require the client and server clocks to be roughly in sync; servers usually accept a small tolerance window (often plus or minus one time step) to absorb minor clock drift.

How is the OTP secret shared in the first place?

During setup the service shows a QR code that encodes an `otpauth://` URI containing the shared secret, the algorithm (HMAC-SHA1 by default, sometimes SHA-256/512), the number of digits (6 by default, sometimes 8) and the type (`totp` or `hotp`). Your authenticator app scans it and stores the secret. From then on both sides compute the same HMAC and compare the resulting code.