🔧 OTP type
TOTP is what Google Authenticator and Authy use. HOTP is for hardware tokens with a counter (YubiKey OATH-HOTP, etc.).
🧾 Identity
🔑 Shared secret (base32)
Uses crypto.getRandomValues. Default 160 bits (RFC 6238 §5.1) for SHA1,
256 bits for SHA-256, 512 bits for SHA-512.
🧮 Algorithm
SHA1 = universal. Google Authenticator ignores this field and always uses SHA1.
📏 Code shape
🔎 Inspect existing otpauth:// URI
📱 Scan this QR with your authenticator
📤 otpauth:// URI
🕒 Live preview (refreshes every {{ period }} s)
⚠️ Compatibility warnings
- {{ w }}
🛡️ Save the secret
Copy the base32 secret into your password manager before sharing the QR. Losing it means re-enrolling MFA on whichever service issued it.
ℹ️ About 2FA TOTP QR Generator
What this tool does
Builds an otpauth:// Key URI and a matching QR code that any standards-compliant authenticator app — Google Authenticator, Authy, 1Password, Microsoft Authenticator, Bitwarden, FreeOTP, Aegis, Raivo — can scan to enroll a second factor. The same URI format also encodes HOTP (counter-based) tokens for hardware-style use cases.
The tool runs entirely in your browser. Your secret never crosses the network during interactive use — URI assembly, base32 encoding, QR rendering, and the live preview code are all computed locally with WebCrypto HMAC.
The otpauth:// Key URI Format
Authenticator apps consume URIs that look like this:
otpauth://totp/Acme%20Corp:alice%40example.com?secret=JBSWY3DPEHPK3PXP&issuer=Acme%20Corp&algorithm=SHA1&digits=6&period=30
otpauth://totp/— scheme + type (usehotpfor counter-based).Acme%20Corp:alice%40example.com— label asIssuer:Account, percent-encoded.secret=…— required base32-encoded shared secret (RFC 4648 §6 alphabet: A-Z and 2-7).issuer=…— recommended; redundant with the label but disambiguates collisions.algorithm=SHA1|SHA256|SHA512— HMAC family. SHA1 is the de-facto default.digits=6|7|8— code length. 6 is universal; 7-8 may not display in all apps.period=30(TOTP) — refresh interval in seconds. 30 is universal.counter=N(HOTP only) — initial counter value.
How TOTP works (RFC 6238)
TOTP derives a short numeric code from a long shared secret plus the current time. The algorithm is:
- Take the current Unix time in seconds and divide by
period(usually 30) — the quotient is the moving factor. - Encode the moving factor as an 8-byte big-endian integer.
- HMAC the 8 bytes with the shared secret (RFC 4226 dynamic truncation).
- Take the resulting integer modulo
10^digits; zero-pad todigitscharacters.
Because the moving factor only changes every period seconds, both server and
client converge on the same code as long as their clocks agree within a few seconds. Most
servers accept the previous, current, and next period codes to absorb small clock drift.
Security ratings and recommendations
-
HMAC-SHA1 (RFC 6238 default) — Secure for TOTP use. The
cryptographic weaknesses of SHA-1 (collision attacks against the hash function) do not
apply to HMAC-SHA1; HMAC's security depends on PRF properties, which SHA-1 retains.
NIST SP 800-107 explicitly permits HMAC-SHA1 for symmetric authentication. Use this for
maximum compatibility — Google Authenticator ignores the
algorithmparameter and always uses SHA1. - HMAC-SHA256 / HMAC-SHA512 — Stronger but less portable. Better future-proofing if your authenticator app and validating server both support them (Authy, 1Password, Aegis, FreeOTP all do; Google Authenticator does not).
- Secret length — RFC 6238 §5.1 recommends a shared secret of at least 128 bits and strongly recommends 160 bits for HMAC-SHA1, 256 bits for SHA-256, and 512 bits for SHA-512. This tool generates 160-bit secrets by default.
- Code length — 6-digit codes give 106 = 1 million possible values. Server-side rate-limiting on failed verifications is required (RFC 6238 §5.2). Without rate-limiting, a 6-digit code is easily brute-forceable.
- Replay protection — RFC 6238 §5.2 requires that a code be accepted at most once per time-step. Servers must reject the previous-time-step code if it has already been used.
- Clock skew — both sides need a clock within ±1 time-step (~30s) of UTC. Devices with NTP synchronisation are reliable; air-gapped offline devices may drift.
- Phishing — TOTP does not protect against real-time phishing proxies (an attacker who relays the code to the legitimate site within the 30-second window). For phishing resistance, use WebAuthn / FIDO2 (passkeys) instead.
Common use cases
- Enrolling 2FA for a user account: build the URI server-side, render the QR, ask the user to scan it. Save the base32 secret in your DB encrypted at rest.
- Re-issuing a backup QR for users who lost their phone but have a recovery code, without rotating the secret.
- Manual entry fallback: provide both the QR and the raw base32 secret so users on devices without a camera can type the secret in by hand.
- Inspecting an existing otpauth URI shared from a password manager, to verify it carries the expected issuer/algorithm/digits/period.
- HOTP setup for hardware tokens (YubiKey OATH-HOTP slot, Feitian, etc.) that use a counter rather than a clock.
Source references
- RFC 6238 — TOTP: Time-Based One-Time Password Algorithm (May 2011).
- RFC 4226 — HOTP: An HMAC-Based One-Time Password Algorithm (December 2005).
- RFC 4648 — The Base16, Base32, and Base64 Data Encodings (October 2006).
-
Google Authenticator Key URI Format — the de-facto spec for the
otpauth://scheme used by every modern authenticator. - RFC 2104 — HMAC: Keyed-Hashing for Message Authentication.
Limits and practical notes
- Your secret is processed entirely in your browser. Nothing leaves your machine during interactive use. The API endpoint exists for server-side enrollment flows.
- The QR code is rendered as inline SVG with no external library — works fully offline.
- Save the base32 secret in your password manager. Losing it means re-enrolling MFA on whichever service issued it.
- Google Authenticator ignores the
algorithmanddigitsURI parameters and always uses SHA1 / 6 digits. If you need non-default values, verify support in your target app first. - The shared algorithm runs in both Node and the browser via the Module-First TypeScript module backing this page.
API Usage Example:
POST /api/tools/security/totp-qr-generator
Content-Type: application/json
{
"operation": "buildUri",
"type": "totp",
"issuer": "Acme Corp",
"account": "[email protected]",
"secret": "JBSWY3DPEHPK3PXP",
"algorithm": "SHA1",
"digits": 6,
"period": 30
}