cipher.ink Write a message

Learn · Practical guides

How 2FA codes (TOTP) work

How the six-digit code in an authenticator app is made from a secret and the clock, with RFC 6238 worked through and a calculator that shows each step.

The six-digit code in an authenticator app is a time-based one-time password (TOTP), a short number that your phone and the website both calculate from a shared secret and the current time. They agree on it without talking to each other. The number changes every 30 seconds. A stolen password alone then isn't enough to log in, but a code can still be phished, and whoever holds the secret can generate every code, so keep it safe. The tool below shows the whole calculation with real numbers.

------

·

How the code was made


  

Check a code

Read an authenticator address

Computed in your browser; nothing is sent anywhere. Even so, do not paste a secret that protects a real account into any web page unless you understand the risk.

What happens when you scan the QR code

When you turn on 2FA with an authenticator app, the website makes a random secret and shows it to you, as a QR code and as a string of letters and digits (base32, what that is). The QR code is just a link of the form otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=Example, which the app reads. Paste such an address into the tool above and you'll see what it holds: the secret, the account name and the settings (six digits, 30 seconds, SHA-1 by default). From then on the app and the server each hold the same secret. The server keeps its copy so it can check your codes, which also means a breach of the server can leak every user's secrets. That's a fact about the design, not a flaw in any one site.

How the code is made

RFC 6238 (TOTP, 2011) standardizes the method, and it builds on RFC 4226 (HOTP, 2005). The box above shows every step with real numbers. Here's the logic:

  1. Take the time in seconds since January 1, 1970, and divide by 30, rounding down. That gives a counter that goes up by one every 30 seconds. For the RFC 6238 test time of 59 seconds, the counter is 1.
  2. Compute an HMAC of the counter (as 8 bytes) under the shared secret, normally with SHA-1 (what HMAC is). The result is 20 bytes that look random and can't be reversed to the secret.
  3. Truncate. The low four bits of the last byte give an offset. Take four bytes starting there, clear the top bit and read them as a number.
  4. Keep the last six digits by taking the remainder after dividing by 106.

Both sides do this independently. The server also knows the time, so it gets the same six digits and compares. Nothing about the code reveals the secret, and an old code is useless once its 30 seconds are over. The RFC's test vectors, such as 94287082 for the secret 12345678901234567890 at time 59 in eight digits, are checked by this site's tests on every deploy, along with the ten HOTP values of RFC 4226.

Why the server accepts the step before

Your phone's clock and the server's are never exactly equal, and typing takes time. A code that was right 20 seconds ago may be rejected when it arrives. So most servers accept the current step and one on either side, and the verify box above does the same and tells you which of the three matched. A code more than one step away fails, which is the usual reason behind "my codes stopped working". The phone's clock has drifted, so turn on automatic time. Servers should also reject a code that was already used, so a code captured within its 30 seconds can't be replayed, though not every site does.

What 2FA protects against, and what it doesn't

  • Stolen or guessed passwords. This is the main benefit. A password leaked from another site, or guessed, no longer opens the account by itself.
  • Not live phishing. A fake login page can ask for your password and your current code and pass both to the real site at once. TOTP doesn't tell you which site you're typing it into. Hardware security keys and passkeys do, because they check the site's address, and they're the better choice for important accounts.
  • Not a stolen secret. Anyone who copies the secret from a backup, a screenshot of the setup QR code or the website's database can create valid codes for as long as the secret exists. Don't keep the QR code or the setup string.
  • Not a stolen unlocked phone or malware that reads the screen.

SMS codes are weaker still. A phone number can be moved to another SIM by fraud (a "SIM swap"), and the message crosses networks that aren't encrypted end to end. If a site offers an app, a key or a passkey, take that over SMS. NIST, the US standards body, treats SMS as a restricted option in its authentication guidance because of those risks.

Setting it up well

  • Save the backup codes the site gives you when you enable 2FA, on paper or in a password manager. They're what lets you in when the phone is lost.
  • Use an app that backs up its secrets securely, or note where each secret is, so a lost phone doesn't mean a lost account. Check how your app handles backup, because a backup not encrypted with a key only you hold would expose every secret.
  • Don't photograph or screenshot the setup QR code. If you must keep the string, store it in a password manager.
  • Turn on automatic time on your phone.
  • Don't make the same phone the only way in to the accounts that matter most, such as your email, which resets all the others.

Common questions

Is a TOTP code the same as the code my bank texts me?

Not quite. A texted code is generated by the bank and sent to you, so it crosses the phone network. A TOTP code is calculated on your device from a secret you already hold, so nothing is sent at login.

Can two devices have the same codes?

Yes, if both hold the same secret. That's how you can add one account to two phones during setup, and it's also how a copied secret lets someone else generate your codes.

Why does the app still work in airplane mode?

It needs only the secret and the clock. Making a code involves no network.

Does cipher.ink use TOTP?

No. It has no accounts and nothing to log in to. The codes appear here because the standard is a good example of how a hash function and a shared secret can prove something without sending the secret. See the TOTP tool and HMAC.

Further reading

  1. RFC 6238: TOTP: Time-Based One-Time Password Algorithm (2011)
  2. RFC 4226: HOTP: An HMAC-Based One-Time Password Algorithm (2005)
  3. NIST SP 800-63B: Digital Identity Guidelines, Authentication and Lifecycle Management
  4. Google Authenticator: Key Uri Format
  5. FIDO Alliance: Passkeys