TOTP Generator
Generate TOTP 2FA codes from a Base32 secret or otpauth:// URI, checked against RFC 6238 test vectors. The secret stays in this tab: not stored, not in the URL.
- Runs in your browser
- Your data never leaves your browser
- Free · No Sign-Up
Scan with WeChat to share this tool
Examples, details and FAQ Worked examples, how it compares with other tools, and answers to common questions.
The code is HOTP from RFC 4226 applied to T = floor(Unix time / period), as defined in RFC 6238 §4. HMAC runs in the browser (Web Crypto).
Examples You Can Reproduce
Each example uses a published test secret, so you can check the output against the RFC or another library.
RFC 6238, SHA-1. Secret GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ (the ASCII string 12345678901234567890 in Base32), 8 digits, Unix time 59:
| Previous | Current | Next | T |
|---|---|---|---|
| 84755224 | 94287082 | 37359152 | 1 |
94287082 is the first row of the table in RFC 6238 Appendix B. The previous code is the time step T = 0; its last six digits, 755224, are the count-0 value in RFC 4226 Appendix D.
RFC 6238, SHA-256. Choose SHA-256 and use the 32-byte seed from the RFC’s reference code: GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQGEZA====. At Unix time 1111111109 the code is 68084774, and the next code, 67062674, is the RFC row for 1111111111, which falls in the next step. The RFC prose names only the 20-byte seed, but its Appendix A code uses 32- and 64-byte seeds for SHA-256 and SHA-512, and the published values only match those. The trailing ==== is accepted; the URI leaves it out.
Cross-check with pyotp. pyotp 2.10.0 gives the same values:
import pyotp
pyotp.TOTP('GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ', digits=8).at(59) # '94287082'
pyotp.TOTP('JBSWY3DPEHPK3PXP').provisioning_uri(name='alice@google.com', issuer_name='Example')
# 'otpauth://totp/Example:alice%40google.com?secret=JBSWY3DPEHPK3PXP&issuer=Example'
Type Example and alice@google.com into Issuer and Account with secret JBSWY3DPEHPK3PXP and the tool builds the same URI. At Unix time 1234567890 that secret gives 742275. It also shows a warning: the key is 80 bits, below the 128 bits that RFC 4226 §4 requires. The secret comes from Google’s Key Uri Format page.
Input errors. GEZDGNBV1Y3TQOJQ is refused because 1 is not in the Base32 alphabet (RFC 4648 §6). The digits 0, 1, 8 and 9 never occur, so they usually mean O, I, B or g was misread. GEZDGNBVG is refused because no Base32 string has 9 characters: a group of 8 cannot end after 1, 3 or 6 characters. pyotp rejects both too (Non-base32 digit found, Incorrect padding).
Checking a Key You Typed by Hand
When a phone cannot scan the QR code, setup pages show the secret as text. Type one character wrong and the app shows codes the server never accepts, with no hint why. Paste the same text here. If the code differs from the app’s code in the same 30 seconds, one of the two copies is wrong. If they match but the service rejects them, check the clock.
Clock errors are common because TOTP depends on both sides agreeing on the time. RFC 6238 §5.2 recommends that a verifier accept at most one step of network delay, and §6 describes a configurable window of steps for drift. pyotp’s verify() has valid_window=0 by default, so a server built on it accepts only the current step. The tool compares your clock with the server’s Date header once, and warns if the difference is more than about 3 seconds beyond the measurement error.
How It Differs from Other Online TOTP Generators
We tested four generators that rank for “totp generator” or “2FA” on 2026-09-30, with the same inputs:
- Invalid characters. With
GEZDGNBV1Y3TQOJQ, totp.danhersam.com showed a code (708688), BrowserScan’s 2FA tool showed a code (its red “invalid key characters” line was also there for the valid RFC secret), and 2fa.cn returned a code. Token2’s TOTP Toolset converted it to a different hex seed without a message. Here it is an error that names the character. - Where the secret goes. BrowserScan writes the key into the address bar (
/2fa#GEZD…), so it ends up in browser history, and its page suggests putting the key in the URL path. 2fa.cn requestedhttps://2fa.cn/codes/<secret>, so the code was computed on its server. Authgear’s page says it saves up to 10 secrets in the browser. This tool keeps the secret in the page’s memory only. - Settings. danhersam has no algorithm choice. Token2’s page is SHA-1 only (SHA-256 is a separate page) with periods of 30 or 60 seconds. Here SHA-1, SHA-256 and SHA-512 and any period from 1 to 86400 seconds are available, plus a fixed Unix time for test vectors.
- otpauth:// input. BrowserScan showed no code for a pasted
otpauth://URI. Here the URI fills in all fields.
Token2 shows several codes around the current time, which is useful for drift checks; this tool shows one step on each side.
Limits
- TOTP only.
otpauth://hotp/URIs are refused, and there is no counter mode. - Digits and algorithms. 6 or 8 digits, as in the Key Uri Format. SHA-1, SHA-256 and SHA-512. The period is a whole number from 1 to 86400 seconds, counted from the Unix epoch (T0 = 0).
- App support. The Key Uri Format page says Google Authenticator ignores
algorithmandperiod, and on Android alsodigits. The tool shows this warning under the QR code when you change any of them. - No QR image input. Decode a screenshot with the QR Code Decoder, then paste the
otpauth://text here. To make a QR code for other text, use the QR Code Generator. - Nothing is saved. Reloading the page clears the secret by design.
- Clock check. The server
Dateheader has one-second resolution, so offsets under about 3 seconds are not reported. If the request fails, no warning appears.
To see the HMAC step on its own, try the HMAC Generator; for account passwords, use the Password Generator.
FAQ
Is my secret sent to a server or saved?
No. The code is computed in your browser with the Web Crypto API. The secret is not written to localStorage, sessionStorage, cookies or the URL, and the page loads no analytics or ad scripts. Reloading the page clears it. The only request the tool makes is one HEAD request for this page, to read the server's Date header for the clock check; it carries no query string and no body.
Why does my code not match the app or the server?
Check three things in this order: the device clock (the tool warns when it is off by more than about 3 seconds), the secret (a character read wrong, or a new secret after the setup page was reopened), and the settings (algorithm, digits and period must match on both sides). The previous and next codes under the current code help when the other side runs a step behind or ahead.
Can I paste the otpauth:// link from a QR code?
Yes. Paste the whole otpauth://totp/ URI into the secret field. The tool fills in the secret, issuer, account, algorithm, digits and period, and keeps only the secret in the field. HOTP URIs (otpauth://hotp/) are refused because the tool generates time-based codes only. To get the URI out of a QR image, decode it with the QR Code Decoder first.
Which secret length should I use?
Random creates 20 bytes (160 bits) for SHA-1, 32 bytes for SHA-256 and 64 bytes for SHA-512, the HMAC output length that RFC 6238 section 5.1 recommends. RFC 4226 requires at least 128 bits; shorter keys still work, and the tool shows their size as a warning.
Should I use this page as my everyday authenticator?
No. Nothing is saved, so the codes are gone when you close the tab, and whoever holds the secret can generate your codes. Keep production secrets in an authenticator app or password manager. Use this page to test a 2FA implementation, to check a key you typed by hand, or to see what code a given secret and time produce.