TOTP Generator

Generate and verify time-based one-time passwords (TOTP) from a base32 secret. Compatible with Google Authenticator and RFC 6238.

One-time passwords, RFC 6238. Generate the current TOTP for a base32 secret and validate a code you received. The counter is derived from the current time, so codes refresh every 30 or 60 seconds. Runs entirely in your browser.

------

Verify a code

How TOTP works

A shared secret plus the clock

TOTP is defined in RFC 6238 and is a thin layer over HOTP. Both sides hold the same secret, usually delivered once as a QR code and stored in an authenticator app. To produce a code, each side takes the current Unix time, divides it by the step size (30 seconds by default) to get a counter, computes HMAC-SHA1 of that counter under the secret, and truncates the result to the required number of digits.

Because the counter comes from the clock rather than from a message, nothing needs to travel between the two parties after enrolment. The server does not send a challenge and the app does not need network access — this is why authenticator apps work in airplane mode.

Truncation and the digit count

The HMAC output is 20 bytes, far more than a 6-digit code. Dynamic truncation uses the low nibble of the last byte as an offset, reads four bytes starting there, masks off the top bit to avoid sign problems, and takes that number modulo 10^digits. Using a variable offset rather than a fixed one means an attacker cannot concentrate analysis on a known slice of the digest.

Six digits is the near-universal default. Eight digits is supported by most apps and buys about two extra decimal digits of guessing resistance, which matters much less than rate limiting does — a 6-digit code has a 1-in-a-million chance per guess, so the real defence is locking out after a handful of failures.

Clock drift and replay

Devices drift. Servers normally accept the code from the previous and next window as well as the current one, giving a ±30 second tolerance. Widening that window past a minute or two starts to meaningfully increase the attack surface and is usually a sign that a device clock needs fixing instead.

Two properties are worth remembering when you deploy this. A code stays valid for its whole window, so an intercepted code can be replayed within that window unless the server marks used counters as spent. And the secret is symmetric: whoever holds the server-side copy can generate valid codes forever, so it needs the same protection as a password database — encrypted at rest, never logged, never in a git repo.

Open-source note: implemented with the browser-native Web Crypto (crypto.subtle) API and a from-scratch base32 decoder. No third-party libraries.

FAQ

Can this replace my authenticator app?
It is useful for testing and for recovering a code when your phone is unavailable, but a browser tab is not a secure place to keep a long-lived shared secret.
Why is my code rejected?
Almost always clock drift. TOTP derives the code from the current UNIX time, so a device more than one 30-second step away from the server produces a code the server has already moved past.
What does the Base32 secret represent?
It is the shared key both sides hold. Base32 is used because it is case-insensitive and avoids ambiguous characters, which makes it practical to type or encode in a QR code.
Why are codes six digits?
RFC 6238 truncates the HMAC to a 31-bit value and takes it modulo 10^6. Six digits balances usability against a one-in-a-million guess rate per attempt, which rate limiting reduces further.
What is the difference between TOTP and HOTP?
TOTP counts 30-second time steps; HOTP counts events and advances only when a code is used. TOTP needs synchronised clocks, HOTP needs synchronised counters.
Can the same code be used twice?
It should not be. A code stays valid for its whole time step, so a server is expected to record which step a user has already consumed and reject a replay.