DevKitHub

API & Security

TOTP Generator and 2FA Code Checker

Paste a Base32 secret or an otpauth:// URI to see the current one-time code, the codes either side of it and how long the current one has left. It is for testing and debugging two-factor set-ups; the secret never leaves this page.

Codes now

Current code
—
Seconds remaining
—
Previous codeone step back
—
Next codeone step ahead
—
Time step (T)
—
Normalised secret10 bytes
JBSWY3DPEHPK3PXP
otpauth URI
otpauth://totp/?secret=JBSWY3DPEHPK3PXP
  • The secret is 10 bytes (80 bits). RFC 4226 requires at least 128 bits and recommends 160, which is 32 Base32 characters.
  • The otpauth URI has no account name, so its label is empty. Add an account (and an issuer) so an authenticator app can tell this entry from the others.

Everything is computed in this page; the secret is not sent anywhere. No QR code is drawn, because that needs a library this page does not load — most authenticator apps also accept the secret typed in as a setup key. This is for testing and debugging: anyone with a secret can make its codes, so do not keep real account secrets in a browser tab.

This tool runs entirely in your browser. Your input is never uploaded, stored or logged.

How it works

A TOTP code (RFC 6238) is an HOTP code (RFC 4226) whose counter is the clock: T is the number of whole periods, normally 30 seconds, since 1970. HOTP takes the HMAC of T written as eight big-endian bytes — HMAC-SHA-1 unless the set-up says SHA-256 or SHA-512 — then uses the low four bits of the last byte as an offset, reads four bytes from there, clears the top bit and keeps the last six to eight decimal digits, leading zeros included. Nothing else goes in, which is why a phone with no signal shows the same code as the server. The codes here are checked against RFC 6238 Appendix B for all three algorithms and RFC 4226 Appendix D. One trap in that appendix: its text says every mode uses the 20-byte seed "12345678901234567890", but the table was generated with a 32-byte seed for SHA-256 and a 64-byte one for SHA-512.

The secret is Base32 (RFC 4648): the letters A to Z and the digits 2 to 7, with no 0, 1, 8 or 9 because they are too easily confused with O, I, L and B. Lower case, spaces between groups and trailing = padding are all accepted; any other character is refused with its position and, for a digit, the letter it probably was. An otpauth://totp/Issuer:account?secret=…&issuer=… URI, the text inside an authenticator QR code, follows Google’s Key Uri Format, whose defaults are SHA1, 6 digits and 30 seconds. When a URI is pasted its own settings are used. Google’s page states that Google Authenticator ignores the algorithm and period parameters, and the digits parameter on Android, so the tool warns whenever a setting differs from the defaults. The URI it builds names the issuer twice, as the format recommends, and omits defaults. No QR code is drawn, because that would need a library this page does not load; most apps also accept the secret typed in as a setup key.

Servers usually accept a code from one step either side of their own, because RFC 6238 recommends allowing at most one step of network delay; a device clock that is further out produces codes for the wrong step, and the checker says which step a code matched. The secret is the whole of the security: anyone who has it can produce every future code, which is why services show it once and hand out recovery codes for when the device is lost. Everything here runs in your browser and nothing is sent anywhere, but this is a testing tool — do not keep real account secrets in a browser tab.

Common problems

Every example below is run against this tool in our test suite, so what it says here is what the tool actually does.

"0" at position 16 is not a Base32 character.

JBSWY3DPEHPK3PX0
Why:
Base32 has no 0, 1, 8 or 9, because they are easily confused with O, I, L and B. A secret retyped from a screen or a printout often has a zero where the letter O belongs.
Fix:
Replace 0 with O, 1 with I or L, and 8 with B. If the value really contains those digits, it is not Base32 — it may be hex.

This is an hotp URI: its codes follow a counter that advances on each use, not the clock.

otpauth://hotp/Example:alice?secret=JBSWY3DPEHPK3PXP&issuer=Example&counter=0
Why:
HOTP (RFC 4226) codes advance by one each time a code is used, so the current code depends on how many have been used and cannot be worked out from the time.
Fix:
Ask the service for a TOTP secret, or use an app that supports HOTP and keeps track of the counter.

The otpauth URI has no secret parameter, and the secret is required.

otpauth://totp/Example:alice@google.com?issuer=Example
Why:
The URI was cut short, or copied from a screen that hides the secret — some admin pages display the URI with the secret removed.
Fix:
Copy the full URI again. The secret is the Base32 value after secret=.

The codes are right here but the server rejects them.

Why:
Clock skew. A code belongs to one 30-second step and servers usually accept one step either side; a device clock that is off by more than that produces codes for a step the server no longer accepts.
Fix:
Turn on automatic date and time on the device. Paste a code into Code to check to see which step it matches.

The app shows 6-digit SHA-1 codes although the URI asks for 8 digits or SHA-256.

Why:
Google’s Key Uri Format page says Google Authenticator ignores the algorithm and period parameters, and the digits parameter on Android, so it computes SHA1, 6-digit, 30-second codes regardless.
Fix:
Keep to the defaults — SHA1, 6 digits, 30 seconds — for anything an unknown app will scan. This tool warns whenever a setting differs.

My SHA-256 code does not match the RFC 6238 test table.

Why:
The appendix text says every mode uses the 20-byte seed "12345678901234567890", but the table was generated with a 32-byte seed for SHA-256 and a 64-byte seed for SHA-512.
Fix:
Use 12345678901234567890123456789012 for SHA-256, and those digits continued to 64 characters for SHA-512.

Frequently asked questions

Why is my 2FA code not working?
Usually the device clock is wrong: codes change every 30 seconds and servers accept only about one step either side. Otherwise the settings differ — algorithm, digit count or period — or the secret was mistyped. Paste the secret here and compare codes, and check a failing code to see which step it matches.
Is it safe to paste a 2FA secret into this page?
The codes are computed in your browser and nothing is sent to any server, which a browser test checks. Even so, a TOTP secret is as sensitive as a password, since anyone who has it can generate your codes. Use this with test accounts and secrets you are debugging, not to store real ones.
What is an otpauth URI?
The text inside an authenticator QR code: otpauth://totp/, a label of issuer and account, then the secret and optional issuer, algorithm, digits and period parameters. The format comes from Google Authenticator’s Key Uri Format and is read by nearly every authenticator app.
What are recovery codes for?
They are single-use codes a service issues when two-factor sign-in is set up, for when the device holding the secret is lost. They do not depend on the clock or the secret, so keep them offline, somewhere other than the phone.

Last updated