WW Tools

TOTP Generator & Code Verifier

Generate a live RFC 6238 TOTP code from a base32 secret. Or paste a code your server rejected and read which time step, algorithm, or digit length actually produces it.

Verify adds a code field. The live code stays on screen in both.
New secret
Algorithm
Digits
Paste a base32 secret to see the live code.

The code is computed in your browser with the Web Crypto API. The secret is never sent anywhere and is not saved. A secret for a real account belongs in an authenticator app, not in any web page.

About TOTP Generator & Code Verifier

This TOTP generator does two jobs. Give it an RFC 4648 base32 secret and it shows the live RFC 6238 code with a countdown, plus the next code and the previous one. Paste a code your server rejected and it names the combination of time step, algorithm, digit length, and period that produces that code, or reports that none of the combinations it checked do.

A TOTP code is not random. It is an HMAC over a counter, and the counter is the Unix clock divided by the period (usually 30 seconds), truncated to six, seven, or eight digits. Because the counter comes from the clock, 'it works on my machine' usually starts with the clock on one of the two machines.

Five things can differ when a code is rejected: the clock, the period, the algorithm, the digit count, and the secret itself. The Verify tab sweeps the first four in one pass, over a bounded window of time steps and the preset periods, and reports how many combinations it compared. That makes a no-match answer one you can check, and it leaves the secret as the one thing the sweep cannot test for you.

The step tape shows the arithmetic behind the code: the time step, the 8-byte big-endian counter, the full HMAC digest, the low nibble that picks the truncation offset, the 31-bit value, and the final mod. That is usually enough to find where your own implementation diverges.

What is absent, and why. No QR code is rendered here; the otpauth:// URI is emitted instead, which is what a QR generator or an authenticator app takes as input. HOTP is recognized but not computed, since it advances on an event counter instead of the clock. Nothing you paste is stored. Every code is computed locally with the Web Crypto API and the secret is never saved. That still does not make a browser the right home for a production secret, so keep this to test secrets and to ones you can rotate the moment you are done.

How to use the TOTP generator

  1. Paste your base32 secret. Case, spaces, and hyphens are all fine, and padding is optional. If you do not have one yet, pick a length and click Generate secret.
  2. Read the live code and the countdown. The next code is shown too, and the previous one whenever there is one, because a server with a one-step tolerance accepts all three.
  3. Set the algorithm, digit count, and period to match your server. SHA-1 with a 30 second period is the RFC 6238 default, and 6 digits is the Key URI default. SHA-256, SHA-512, 7 or 8 digits, and any period from 1 to 3600 seconds are all here, with 15, 30, and 60 as one-click presets.
  4. Open the step tape. It shows every intermediate value between the clock and the code, so you can compare them line by line against what your own implementation produces.
  5. Switch to Verify and paste the code your server rejected.
  6. Read the verdict. It names the time step that matched and which way your clock is off, or the algorithm that matched instead, or the digit length, or it reports that none of the combinations checked do. The count is on screen either way. Only candidates the same length as the code you pasted can compare equal, so that is the only length swept, and the number you see is the number actually compared.
  7. Paste an otpauth:// URI to fill every field at once, or fill in an issuer and account and copy the URI back out.
  8. Turn off Follow the clock to compute at any Unix second. Or load one of the RFC 6238 Appendix B vectors and watch the page reproduce the published code.

Common Use Cases

Wire a TOTP fixture into an integration test

Freeze the timestamp, take the code, and assert against it without a phone in the loop. The Unix-seconds field takes any whole second from 0 to 100,000,000,000, so a test that pins the clock to 1234567890 can pin the expected code to the same second.

Debug an enrollment flow that rejects the code the app shows

Paste the rejected code and read which axis is wrong, instead of guessing between five candidates. The verdict names the time step, the algorithm, the digit length, or the period, and says how many combinations it compared to get there.

Read an otpauth:// URI without scanning the QR

Paste the URI and every parameter comes out separated and editable, including the issuer, which is split between the label prefix and the issuer parameter. No QR code is rendered here. The URI is the exchange format in both directions.

Check your own TOTP implementation against the spec

The RFC 6238 Appendix B vectors load in one click with the correct per-algorithm seed. The step tape then shows the counter, the digest, and the truncation offset, so you can see which line of your code diverges.

Frequently Asked Questions

Why does my TOTP code not match what the server expects?

Ranked by how often each one turns out to be the cause: (1) clock drift, where one side is a step or two off and the code is technically valid for a step the server is no longer accepting; (2) the period, usually a 30 second client against a 60 second server; (3) the algorithm, usually SHA-1 against SHA-256, which is easy to get wrong because Google Authenticator ignores the algorithm parameter in a provisioning URI, so the SHA1 default applies; (4) the digit count, 6 against 8; (5) the secret itself, either transcribed with a character wrong or handed over as hex when base32 was expected. The Verify tab settles the clock, the algorithm, and the digit length in one pass: it sweeps a bounded window of time steps across all three algorithms at the digit length you pasted, and names what matched. With 'Also try the other periods' on, it additionally probes whichever of 15, 30, and 60 you are not already using, at the current step only, so a server running some other period, 45 say, is not covered. If nothing matches, the count of combinations compared is shown next to the verdict, and the secret is the remaining suspect.

Is it safe to enter a 2FA secret into a website?

The honest answer has two halves. On this page the computation is local. The code is produced by the Web Crypto API in your browser, the secret is not sent anywhere, and nothing you paste is written to storage. The control values (algorithm, digits, period, drift window) persist in this browser so the page comes back the way you left it; the secret, the code, the issuer, the account, and the URI never do. The share link is built in the browser too, and it puts the secret in the URL fragment only if you explicitly pick the option that includes it. The other half: a secret for a real account still belongs in an authenticator app rather than in any web page, because anything pasted into a browser can be read by an extension or left behind in a screenshot. Use this with test secrets, secrets you are in the middle of enrolling, or a secret you are debugging and can rotate afterwards.

How much clock drift will a server tolerate?

Clock skew tolerance is normally one step either side of the current step, which with a 30 second period is a 90 second effective window. That is why this tool shows the previous and next codes as well as the current one. Verify sweeps from T-N to T+N, closest first, and reports the signed offset that matched, which is the clock skew measured in steps. A negative offset means this browser's clock is ahead of whatever produced the code; a positive offset means it is behind. Read that number with one caveat. A code entered a minute late looks exactly like a clock that is ahead, because both produce a match at an earlier step. If the offset is consistent across attempts, it is a clock. To read your machine's Unix time in human form, the timestamp converter is quicker. A known-good reference has to come from outside the browser, such as an NTP query or a time service, because every clock on this site is your own.

What is a base32 secret, and how do I tell base32 from hex?

RFC 4648 base32 uses 32 characters: A to Z, plus 2 to 7. The alphabet has no 0, no 1, no 8, and no 9, so a string containing any of those digits is not base32. It is usually hex, which uses 0 to 9 and a to f, and this page names that case rather than failing silently. Case does not matter and neither do spaces or hyphens, and the = padding is optional in a provisioning URI, where the Key URI format says to omit it. On length, RFC 4226 requires at least 128 bits of shared secret and recommends 160, which is 16 and 20 bytes, or 26 and 32 base32 characters. Generate secret produces a random base32 secret at 10, 16, 20, 32, or 64 bytes, and the strength read next to it is measured against those two thresholds.

Which parameters does an otpauth:// URI carry, and which apps honor them?

The Key URI format, which plenty of tooling and documentation calls an otpauth URL, has a type (totp or hotp), a label of issuer:account, and the parameters secret (required), issuer (strongly recommended, and it should match the label prefix), algorithm (default SHA1), digits (default 6), period (default 30), and counter, which is required for hotp only. Two honoring facts come straight from Google's Key URI documentation: Google Authenticator ignores the algorithm and period parameters, and some Android and BlackBerry implementations ignore digits. For any other app, read its own documentation rather than trusting a list. This page parses and builds the URI in both directions and reports what it found: a missing secret, a padded secret, an issuer that disagrees with the label, an unknown parameter, or a broken percent-escape. An otpauth://hotp/ URI is parsed and its counter is shown, but HOTP is recognized here and not computed, because it counts events rather than time steps.

How is a TOTP code computed, and what are the RFC 6238 test vectors?

Take the Unix time, subtract T0 (normally 0), divide by the period and floor it. That is the counter T. Write T as 8 big-endian bytes and HMAC those bytes with the secret as the key, then apply RFC 4226 dynamic truncation: read the low 4 bits of the last digest byte as an offset, take the 4 bytes at that offset, mask off the top bit of the first one to get a 31-bit value, and reduce it modulo 10^digits with zero padding. The step tape on this page shows each of those values. The published vectors have one trap. RFC 6238 Appendix B uses a different ASCII seed per algorithm, 20 bytes for SHA-1, 32 for SHA-256, and 64 for SHA-512, which is the correction in the errata rather than the one shared 20-byte seed the original prose implies. At t = 59 the expected 8-digit codes are 94287082 for SHA-1, 46119246 for SHA-256, and 90693936 for SHA-512. Any of the 18 rows loads in one click. The digest in the middle of all this is an ordinary HMAC over the 8 counter bytes, and the step tape prints it in full, so you can line your own implementation up against it byte for byte.