otpauth:// URI generator
Build a standard otpauth:// provisioning URI from an issuer, account, and base32 secret — encode it as a QR code to set up any authenticator app. Runs in your browser; the secret never leaves your device.
About this tool
This tool builds a standard otpauth:// provisioning URI — the Key Uri Format
understood by Google Authenticator, Authy, 1Password, Microsoft Authenticator, and
virtually every other authenticator app. Encode the resulting URI as a QR code and scan
it to add a new two-factor (2FA) account, or paste it directly into an app that accepts
setup links.
Everything runs locally in your browser. The secret you enter is never sent to a server.
What goes into the URI
- Type —
totp(time-based, the usual rolling 2FA codes) orhotp(counter-based). - Issuer — the provider or organization name shown in the app (e.g.
GitHub). Recommended so accounts are easy to tell apart. - Account name — the username or email the codes are for. It must not contain a colon.
- Secret — the shared secret, base32-encoded (RFC 4648). Spaces and letter case are ignored.
- Digits — how many digits each code has (6, 7, or 8; default 6).
- Period — the TOTP time step in seconds (default 30; ignored for HOTP).
- Algorithm — the HMAC hash:
sha1(the authenticator-app standard),sha256, orsha512. - Counter — the HOTP starting counter value (default 0; ignored for TOTP).
The format
otpauth://TYPE/ISSUER:ACCOUNT?secret=SECRET&issuer=ISSUER&algorithm=ALG&digits=N&period=SECONDS
The label and issuer are percent-encoded so values with spaces or special characters stay valid.
For HOTP, period is replaced by counter.
FAQ
Why is my secret being rejected?
The secret must be base32 (RFC 4648): only the letters A–Z and digits 2–7,
with optional = padding. Spaces and dashes are stripped and lowercase is fine —
jbsw y3dp ehpk 3pxp works — but characters like 0, 1, 8, or 9 mean the
string isn't base32 and the tool errors instead of producing a URI your app can't
import.
Should I change the algorithm, digits, or period?
Usually not. sha1, 6 digits, and a 30-second period are what the service you're
pairing with almost certainly expects, and several authenticator apps silently
ignore non-default values — which would make your codes wrong. Only deviate
(sha256/sha512, 7–8 digits, other periods) when the service's docs explicitly say
so. Digits outside 6–8 are rejected.
What's the difference between TOTP and HOTP?
totp codes roll over on a timer (the period, default 30 s) — this is what
nearly every 2FA setup uses. hotp codes advance on a counter instead: the URI
carries a starting counter value (default 0) and the period is ignored. Pick
HOTP only if the service explicitly issues counter-based tokens.
Why can't the account name or issuer contain a colon?
The URI's label is issuer:account, so a literal colon inside either value would
change where the split happens when the app parses it back. The tool rejects
colons up front; everything else (spaces, @, unicode) is fine because the label
and issuer are percent-encoded.
Developer & Automation Access
Run it from the terminal
Same engine as this page, headless — via the gizza CLI:
gizza tool otpauth-uri 'type=totp'New to the CLI? Get gizza →
Open it by URL
Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:
https://gizza.ai/tools/otpauth-uri/?type=totp&issuer=GitHub&account=alice%40example.com&secret=JBSWY3DPEHPK3PXP&digits=6&period=30&algorithm=sha1&counter=0Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.
