---
url: https://findutils.com/blog/how-2fa-codes-work-totp-explained
title: "How 2FA Codes Work: TOTP and the 30-Second Clock Explained"
description: "How an authenticator app makes a six-digit code from a secret and the clock, why codes fail when the time is off, and what TOTP does and does not protect."
category: security
content_type: blog
cluster: authentication
locale: en
read_time: 8
status: published
author: "olgunozoktas"
published_at: 2026-10-19T08:08:00Z
excerpt: "Your authenticator app and the website never talk to each other, yet they agree on the same six digits every 30 seconds. This post walks through the TOTP math with the official test vector, explains why codes get rejected, and shows what one-time codes cannot stop."
tag_ids: ["security", "two-factor-authentication", "totp", "authentication", "privacy"]
tags: ["Security", "Two-Factor Authentication", "TOTP", "Authentication", "Privacy"]
primary_keyword: "how do 2fa codes work"
secondary_keywords: ["totp explained", "time-based one-time password", "why is my 2fa code not working", "authenticator app codes", "totp secret key", "totp vs hotp"]
tool_tag: "two-fa-code-tester"
related_tool: "two-fa-code-tester"
related_tools: ["two-fa-code-tester", "hmac-generator", "unix-timestamp", "qr-code-generator", "password-generator", "password-breach-checker"]
updated_at: "2026-10-19T08:08:00Z"
og_image: "/images/content/blog/how-2fa-codes-work-totp-explained-cover-20261019.webp"
image_alt: "A phone shows six code tiles under a circular 30-second countdown ring, while a small key and a clock face on either side feed into it along dotted lines."
---

A two-factor code from an authenticator app is a time-based one-time password (TOTP). When you set up 2FA, the website and your app store the same secret key. Every 30 seconds, both take the current time, count how many 30-second steps have passed since 1970, run that number and the secret through HMAC-SHA1, and cut the result down to six digits. The app and the server never talk to each other: they get the same code because they share the secret and the clock.

This post walks through each step with the official test values, then covers why codes get rejected and what TOTP does not protect you from. To watch it happen, paste a test secret into the FindUtils [2FA Code Tester](/security/two-fa-code-tester/), which shows the current code and the seconds left before it changes.

## Where the secret comes from

At setup, the website creates a random secret and shows it as a QR code, usually with a text version for manual entry. The QR code holds a URI in the [Key URI format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format) that Google Authenticator documented and other apps also read:

```text
otpauth://totp/Example:alice@google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example
```

The `secret` is written in Base32 ([RFC 4648](https://www.rfc-editor.org/rfc/rfc4648#section-6)), which uses only the letters A to Z and the digits 2 to 7, five bits per character. The digits 0, 1, 8 and 9 never appear, which avoids confusing 0 with O and 1 with I when you type a key by hand. Optional parameters set the hash (`algorithm`, default SHA1), the code length (`digits`, 6 or 8, default 6) and the step (`period`, default 30 seconds). The same page notes that Google Authenticator currently ignores the `algorithm` and `period` parameters, so a service that changes them may not work with every app.

After scanning, the app keeps the secret on your phone. It never needs to send anything back.

## How the six digits are calculated

TOTP is defined in [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238). It builds on HOTP ([RFC 4226](https://www.rfc-editor.org/rfc/rfc4226)), a counter-based one-time password, and replaces the counter with time. RFC 6238 includes test vectors that use the ASCII secret `12345678901234567890` (in Base32: `GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ`). Here they are step by step.

### Step 1: Turn the time into a counter

Take the current [Unix time](/developers/unix-timestamp/), the seconds since 1970-01-01 00:00:00 UTC, and divide it by the 30-second step, dropping the remainder. At Unix time 59, the counter is `59 / 30 = 1`. It stays 1 until second 60, when it becomes 2. The counter is written as an 8-byte number: `0000000000000001`.

### Step 2: Sign the counter with HMAC-SHA1

The counter bytes are the message and the secret is the key. HMAC-SHA1 returns 20 bytes:

```text
75a48a19d4cbe100644e8ac1397eea747a2d33ab
```

This is the same HMAC that webhook providers use to sign requests; the [HMAC guide](/guides/hmac-generator-guide/) covers it in detail. RFC 6238 also allows HMAC-SHA256 and HMAC-SHA512, but SHA-1 is the default that almost every authenticator setup uses.

### Step 3: Pick four bytes (dynamic truncation)

The last byte is `ab`. Its lowest four bits, `b`, give the offset 11. The four bytes starting at byte 11 are `c1 39 7e ea`. Clearing the top bit (so the number is never negative) gives `0x41397eea`, which is 1,094,287,082.

### Step 4: Keep the last six digits

`1094287082 mod 1,000,000 = 287082`. That is the code. With eight digits it is `94287082`, exactly the value in the RFC's table for SHA-1 at time 59. If the result has fewer than six digits, it is padded with leading zeros, which is why codes such as `081804` are normal.

The [2FA Code Tester](/security/two-fa-code-tester/) runs these four steps for the current time, once a second, so you can see a code change the moment the counter moves on.

## Why a 2FA code gets rejected

### The clock is off

Both sides compute the counter from their own clock. If your phone is a minute slow, it shows the code for a step that the server has already left. RFC 6238 handles normal delay by recommending that the server accept "at most one time step" for network delay, and suggests a configurable limit for clock drift beyond that. A phone set to automatic network time fixes almost every case.

### You typed the code as it changed

A code typed in the last second or two of its step can arrive in the next step. That is why RFC 6238 lets a server accept the code of the previous step as well. The 2FA Code Tester is stricter: its Verify button compares your entry with the current code only, so a code from the previous 30 seconds shows as invalid there even if a website would still accept it.

### The secret was copied wrongly

One wrong character gives a different code every time. Watch for the digits 0, 1, 8 and 9, which are not valid Base32. Spaces and lowercase letters are harmless in the tester: it uppercases the key and ignores spaces.

### The service uses different settings

If a service sets `digits=8`, `period=60` or `algorithm=SHA256`, an app or tester that assumes 6 digits, 30 seconds and SHA-1 shows a different code. The FindUtils tester uses the standard settings (SHA-1, 6 digits, 30 seconds), so it matches the large majority of setups but not these variations.

### It is HOTP, not TOTP

An `otpauth://hotp/` key counts button presses instead of time. Its codes do not change by themselves, and a time-based tester will never match them.

## What TOTP protects and what it does not

A six-digit code has one million possible values, so guessing it is hard only if the server limits attempts. RFC 4226 recommends throttling for exactly this reason, and it requires a shared secret of at least 128 bits (160 bits recommended, which is 32 Base32 characters). The tester's Sample button makes a 16-character secret, which is fine for trying the tool but shorter than a real service should issue.

TOTP stops an attacker who has only your password. It does not stop phishing. A fake login page can ask for your password and your current code and pass both to the real site within the 30 seconds. NIST's digital identity guidelines ([SP 800-63B](https://pages.nist.gov/800-63-4/sp800-63b.html)) state plainly that "OTP authentication is not phishing-resistant", because a typed code is not tied to the site you type it into. Passkeys and security keys (FIDO2/WebAuthn) are, because the browser checks the site before it signs anything.

Compared with SMS codes, TOTP codes are made on your phone and never travel over the phone network, so a SIM swap does not expose them. The trade-off is the secret itself: anyone who copies it can make your codes forever. Treat the QR code and the setup key like a password, and save the backup codes the service gives you.

## Testing TOTP safely

If you build a login with 2FA, test it with secrets you create for that purpose, not with the secret of a real account. The [2FA Code Tester](/security/two-fa-code-tester/) computes codes in your browser, which makes it handy for checking your server's codes against an independent implementation. To try the full setup flow on a phone, put a test `otpauth://` URI into the [QR Code Generator](/generate/qr-code-generator/) as plain text and scan it with your authenticator app. And keep the first factor strong: a unique password from the [Password Generator](/security/password-generator/), checked with the [Password Breach Checker](/security/password-breach-checker/), matters as much as the code.

## Key takeaways

- A TOTP code is HMAC-SHA1 of the 30-second time step, keyed with the secret from setup, cut down to six digits.
- Your app and the server never communicate; they agree because they share the secret and the time.
- Most rejected codes come from a wrong phone clock, a mistyped Base32 key, or non-standard digits, period or algorithm.
- TOTP blocks password-only attacks but can be phished; passkeys and security keys cannot be relayed the same way.
- The secret is the real credential: protect the QR code, and keep the backup codes.

## FAQ

### How do 2FA codes work without internet?

The code depends only on the secret stored on your phone and the current time. Both are available offline, so the app can make codes in airplane mode. Only the clock needs to be right.

### Why does my 2FA code not work?

The most common cause is a phone clock that is off by more than about 30 seconds. Set the time to automatic. If the time is right, the secret may have been entered wrongly, or the service may use 8 digits, a 60-second period or SHA-256.

### What is the difference between TOTP and HOTP?

HOTP (RFC 4226) makes a new code from a counter that goes up each time you request one. TOTP (RFC 6238) uses the number of 30-second steps since 1970 as the counter, so the code changes on its own.

### Is TOTP safer than SMS codes?

It avoids SIM-swap and interception risks because the code is made on your device. Neither TOTP nor SMS codes stop a phishing page that relays your code in real time.

### Can I test my 2FA secret online?

Yes, with a test secret. Paste it into the FindUtils 2FA Code Tester to see the current code and verify one. On the tool page the codes are computed in your browser and the secret is not sent to a server.

### What is a Base32 secret key?

It is the 2FA secret written with the letters A to Z and the digits 2 to 7, as defined in RFC 4648. It is the text version of the QR code you scan at setup.

## Related reading

- [HMAC Generator: create and check HMAC-SHA256 signatures](/guides/hmac-generator-guide/)
- [How to generate secure passwords](/guides/how-to-generate-secure-passwords/)
- [Unix timestamps: seconds vs milliseconds](/blog/unix-timestamp-seconds-vs-milliseconds/)
- [Is it safe to decode a JWT online?](/blog/is-it-safe-to-decode-a-jwt-online/)

## Sources

- [RFC 6238: TOTP: Time-Based One-Time Password Algorithm](https://www.rfc-editor.org/rfc/rfc6238)
- [RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm](https://www.rfc-editor.org/rfc/rfc4226)
- [RFC 4648: The Base16, Base32, and Base64 Data Encodings](https://www.rfc-editor.org/rfc/rfc4648)
- [Google Authenticator wiki: Key Uri Format](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
- [NIST SP 800-63B: Authentication and Authenticator Management](https://pages.nist.gov/800-63-4/sp800-63b.html)
