What this tool does
A TOTP code is an HOTP code whose counter comes from the clock. Server and app share a secret key, for example 20 random bytes, written in Base32. Both compute T = floor((Unix time − T0) / X), where X is the period (30 seconds by default) and T0 is 0. They write T as an 8-byte big-endian number, compute HMAC-SHA-1 of it with the key, and take 31 bits from the result at an offset given by the last byte’s low 4 bits (dynamic truncation, RFC 4226 §5.3). That number modulo 10^6 is the 6-digit code. Codes shows the current code with a countdown, the previous and next codes, T in decimal and hex, the Unix time used and every intermediate value. Check a code tells you whether a code is valid now or matches a nearby step, and what clock difference that implies. If nothing matches, it tries the other algorithms, 30 and 60 second periods, and the code’s own number of digits. Setup QR builds the otpauth:// URI (Google’s Key Uri Format) with the label and parameters percent-encoded, and its QR code. HOTP mode uses a counter you set instead of the clock. The secret can be Base32 (any case, spaces and padding allowed), hex or plain text.
Example input and output
Secret (Base32): GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ (ASCII "12345678901234567890")
Algorithm: SHA-1 · Digits: 8 · Period: 30 s · T0: 0
Unix time: 59T = floor(59 / 30) = 1 (0x0000000000000001)
Current code: 94287082
Previous (T − 1): 84755224
Next (T + 1): 3735915294287082 is the RFC’s first test vector. Load it with RFC example. For SHA-256 and SHA-512 the RFC uses the same digits repeated to 32 and 64 bytes, and gives 46119246 and 90693936 for this time.
Secret: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ · SHA-1 · 8 digits · 30 s
Unix time: 1111111111
Code: 07081804
Window: ±1 stepValid within the window: it matches the previous 30-second step (T − 1 = 37037036)
Either it was typed after it expired, or the clock that made it is 2–31 s behind this one.07081804 is the RFC’s code for Unix time 1111111109. That is only two seconds earlier, but a new step started at 1111111110. A server that checks only the current step rejects it; RFC 6238 recommends allowing one step for network delay.
Issuer: ACME Co
Account name: alice@example.com
Secret: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ · SHA-1 · 6 digits · 30 sotpauth://totp/ACME%20Co:alice@example.com?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30The space is %20, not +. The issuer appears twice, as the label prefix and as the issuer parameter, as the Key Uri Format recommends. The QR code encodes exactly this text.
Common errors and fixes
- Every code is rejected, even though the secret is right
- Usually one of the clocks is wrong. TOTP uses Unix time, which is UTC, so the time zone doesn’t matter, but a clock that is a minute off does. Turn on automatic time on the phone and NTP on the server. Paste a rejected code into Check a code: if it matches T − 1 or T + 1, the clocks differ by about one period, and the tool tells you in which direction.
- Character 2 is “1”, which isn’t in the Base32 alphabet (A–Z and 2–7). The whole secret looks like hex
- Authenticator apps and otpauth:// URIs use Base32, but some servers store the key as hex or as raw text. Set the secret format to Hex or Text, and the tool shows the same key as Base32 to give to the app. Using the hex digits as if they were Base32 gives a different key and wrong codes.
- The app shows codes, but they never match the server
- Check that both sides use the same algorithm, number of digits and period. Many authenticator apps support only SHA-1, 6 digits and 30 seconds, and some ignore other values in the otpauth:// URI without warning. When a code doesn’t match, Check a code tries the other algorithms, 30 and 60 second periods and the code’s own number of digits, and says which settings fit.
- The account appears in the app as “ACME+Co” or with %20 in its name
- The label was encoded for an HTML form, where a space becomes +. In the otpauth:// path a + is a literal plus, so encode spaces as %20 (encodeURIComponent in JavaScript, urllib.parse.quote in Python). If the app shows %20, the label was encoded twice.
- Remove the colon from the issuer: the label uses a colon to separate the issuer from the account name.
- The label is Issuer:account, and the Key Uri Format says neither part may contain a colon, even percent-encoded. Use “ACME Co” rather than “ACME: Co”, or put the full name in the issuer parameter only.
- The same code is accepted twice
- RFC 6238 §5.2 says the verifier MUST NOT accept a second use of a code after it has accepted it once. Store the last accepted time step for each user and refuse codes for that step or an earlier one. With HOTP, set the counter to one past the code you accepted.
Common use cases
- Testing a two-factor sign-in flow without reaching for a phone
- Debugging codes a server rejects: clock skew, the wrong algorithm, digits or period, or a hex key used as Base32
- Building and checking the otpauth:// URI and QR code for an enrolment screen
- Checking your own TOTP or HOTP code against the RFC 6238 and RFC 4226 test vectors
- Making codes for a fixed Unix time to reproduce a bug report or write a unit test
Privacy and security notes
- Codes are computed with Web Crypto HMAC, and new secrets come from crypto.getRandomValues, in this browser tab. Nothing you generate or paste is sent to DevPrix or stored on a server.
- Share copies a link without your values, and Send to is not offered: the secret never goes in a URL or the address bar. Reloading the page makes a new random secret.
- The QR code is drawn in the page from the URI. Treat a screenshot of it like the secret itself.
Frequently asked questions
What is the difference between TOTP and HOTP?
Both are HMAC of a counter, truncated to a few digits. HOTP (RFC 4226) uses a counter that goes up by one each time a code is used, so the server must track it. TOTP (RFC 6238) uses the number of 30-second steps since 1970 as the counter, so both sides only need the same clock. Most sign-ins with an authenticator app use TOTP.
Which settings work in every authenticator app?
SHA-1, 6 digits and a 30-second period, the defaults in the Key Uri Format. SHA-256, SHA-512, 8 digits or 60 seconds are valid in RFC 6238, but support varies between apps, platforms and versions, and some apps ignore these parameters without telling you. Use the defaults unless you control the app, or test with the apps your users have.
How long should a TOTP secret be?
RFC 4226 requires at least 128 bits and recommends 160 bits (20 bytes), and RFC 6238 says keys should be as long as the HMAC output: 20 bytes for SHA-1, 32 for SHA-256 and 64 for SHA-512. Those are the sizes New secret uses. Some services issue 80-bit secrets (16 Base32 characters), like the Key Uri Format’s own example; they work, but they are below the RFC minimum.
How many time steps should a server accept?
RFC 6238 recommends allowing at most one step for network delay, so a typical server accepts the previous, current and next codes: a window of ±1, or about 90 seconds in total. A wider window makes guessing easier and doesn’t fix a clock that is far off. Limit failed attempts too, as RFC 4226 §7.3 asks.
Why do the RFC 6238 SHA-256 and SHA-512 test vectors fail in my code?
The RFC’s text names a single seed, the ASCII string 12345678901234567890, but its table was computed with that string repeated to 32 bytes for SHA-256 and 64 bytes for SHA-512, as its reference code does. RFC example loads the right seed for the algorithm you pick.
Guides
- How TOTP 2FA codes work, step by stepA TOTP code is an HMAC of the time step, cut to 6 digits. The RFC 4226 and RFC 6238 maths worked through, plus otpauth:// enrolment and server-side checks.