TOTP / 2FA code generator
Generate a 2FA secret, its enrollment QR and the live 30-second code, and verify submitted codes — all offline, with nothing stored.
- Runs in your browser
- Nothing you enter is sent
- Free, no account
Valid for 30 more seconds
What an authenticator app stores. 160 bits (32 characters) is the RFC 4226 recommendation.
Shown as the account provider.
Usually an email or username.
Google Authenticator and most hardware tokens only implement SHA1.
Six is near-universal.
RFC 6238 recommends 30 seconds; some banks use 60.
otpauth://totp/onthisdevice:demo%40example.com?secret=&issuer=onthisdevice&algorithm=SHA1&digits=6&period=30The QR image is drawn on this page from the URI above. It is never uploaded, which matters more here than anywhere else on the site: this string is the entire second factor.
How a six-digit code is produced
TOTP is RFC 6238, and it is a thin wrapper around RFC 4226's HOTP. The whole algorithm is four steps:
- Take the current Unix time in seconds and divide it by the step, normally 30. That integer is the counter.
- Write the counter as an 8-byte big-endian value and compute HMAC-SHA1 of it with the shared secret.
- Take the low four bits of the last byte as an offset, read four bytes from that offset, and clear the top bit — this is the “dynamic truncation” that turns 160 bits into 31.
- Take that number modulo 10⁶ and pad to six digits.
Everything above happens in this tab, using the browser's native WebCrypto for the HMAC. Watch the countdown roll over and the code change: no request is made at any point.
Why this page is the sharpest demonstration of local execution
A 2FA secret is the entire second factor. Pasting one into a website that sends it anywhere is about the worst thing you can do with it — and a visitor has no way to tell from the interface which kind of site they are on.
So test this one rather than trusting it. Open DevTools, clear the Network panel and let the
code cycle: nothing appears. Turn off Wi-Fi entirely and reload: the page still works. Read the
response headers and you will find a Content-Security-Policy with no third-party origin in
connect-src, which means the browser itself would block an upload even if the
code attempted one.
Reading the otpauth URI
otpauth://totp/Example:alice@example.com
?secret=JBSWY3DPEHPK3PXP
&issuer=Example
&algorithm=SHA1
&digits=6
&period=30 | Parameter | Meaning | Practical note |
|---|---|---|
secret | The shared key, Base32 | The only part that is actually secret |
issuer | Service name | Shown as the heading in the app; also repeated in the label |
algorithm | SHA1, SHA256 or SHA512 | Google Authenticator ignores anything but SHA1 |
digits | 6, 7 or 8 | Most apps ignore 7 and 8 |
period | Seconds per step | 30 almost everywhere; some banks use 60 |
A QR code is nothing more than that string rendered as a bitmap. Scanning it transfers the URI and nothing else.
When codes are rejected
- Clock skew. TOTP depends on the time. A device more than about 30 seconds out will fail; servers usually accept ±1 step, and this page verifies with the same tolerance.
- Wrong algorithm. If a service issued a SHA-256 secret and your app assumes SHA-1, every code is wrong and nothing indicates why.
- Secret transcribed by hand. Base32 excludes 0, 1 and 8 precisely because people mistype them — if your secret contains one of those digits, it is not valid Base32.
- Code already used. Well-built servers reject a replayed code even inside its window.
What this page is for, and what it is not
It is useful for testing a 2FA integration, checking whether a secret is valid, generating a key for a service you are building, or reading a code from a secret you already hold. It is not an authenticator app: nothing is stored, so a refresh clears everything. Keep your real secrets in a dedicated app or hardware key, and keep the recovery codes somewhere else entirely.
Questions
Is it safe to put a 2FA secret into a web page?
Into this one, the risk is the page reaching a server — and it cannot: the QR is drawn locally, the HMAC runs in WebCrypto, and our Content-Security-Policy lists no external origin. Turn off Wi-Fi and the tool still works. Never paste a live secret into a page that fails those tests.
Why does my code differ from my phone?
Clock skew, or mismatched parameters. TOTP is derived from the current 30-second window, so a phone more than a few seconds out drifts. Also check digits and algorithm — Google Authenticator only implements SHA1 with 6 digits.
What is inside the otpauth:// URI?
The Base32 secret, the issuer and account labels, the algorithm, digit count and period. Scanning the QR simply hands the authenticator app that string — nothing else is exchanged.
How is the code actually computed?
Take the Unix time divided by 30 as a 64-bit counter, HMAC it with the secret, then dynamically truncate the result to a 31-bit number and take it modulo 10⁶. That is RFC 6238 in one sentence.
Does this replace my authenticator app?
No, and it should not. Nothing is stored here — refresh and the secret is gone. Use it for testing an integration, verifying a code, or recovering a secret you already hold.