Developer Security

TOTP secret generator

Strength Excellent
160 bits of entropy · guessed in about 2,315,609,611,204,437,200,000 eons

Generated in your browser · never sent, never stored

Local · 160 bits, base32, RFC 4648

Time-based one-time passwords work from a secret both the server and the authenticator app hold. This generates that secret: 160 random bits, base32-encoded without padding, which is the form every authenticator app expects.

How to generate a TOTP secret

1 Fill in the issuer. Your service’s name, and the account it belongs to. Both appear in the user’s authenticator app.
2 Copy the base32 secret for your own storage, and the otpauth URI for the QR code you show the user.
3 Show the base32 string next to the QR code as well, so someone on a desktop authenticator can type it in.
4 Store the secret encrypted at rest. Anyone holding it can generate valid codes.
5 Generate again for the next account. Every enrolment needs its own secret, never a shared one.

Why the defaults look dated and should stay

SHA-1, six digits and a thirty-second period are what RFC 6238 sets out and what every mainstream authenticator implements. The RFC does permit HMAC-SHA-256 and HMAC-SHA-512, and the URI format has parameters for digits and period, but the apps people actually have on their phones largely ignore anything but the defaults, so a non-default enrolment produces codes that never match and a support ticket nobody can diagnose from the server side. Nothing is lost by staying put. The attack this construction has to survive is guessing a six-digit code inside a thirty-second window, which is a rate-limiting problem rather than a hashing one, and the collision weaknesses that retired SHA-1 elsewhere do not touch HMAC.

The secret is a symmetric key, and both ends hold it

Unlike a password, which you can store as a one-way hash and never need back, a TOTP secret has to be recoverable by your server on every login, because the server recomputes the same code the phone shows. That makes it closer to an API key than to a credential: encrypt it at rest with a key held outside the database, keep it out of logs and out of error reports, and never return it from an API after enrolment. A leaked secrets table is a leaked second factor for every user in it, and rotating means re-enrolling every one of them by hand.

What the server has to do that this page cannot

Generating the secret is the easy half. Validation is where implementations go wrong. Accept a small window either side of the current step, because phone clocks drift and people take a second to type; RFC 6238 recommends allowing at most one step of network delay, so one step back and one forward is the usual choice and a wider window buys an attacker proportionally more guesses. Record the last step number a user successfully used and refuse anything at or before it, or a code stays replayable for the rest of its thirty seconds. Rate-limit attempts hard, since six digits is a million possibilities and an unthrottled endpoint is brute-forceable in an afternoon. Issue single-use recovery codes at enrolment, because a lost phone otherwise locks the account out permanently.

What the URI carries

The otpauth scheme is not an IETF standard; it is the Key URI format Google Authenticator defined and everyone else adopted. The label is the issuer and account joined by a colon, and the issuer is repeated as a query parameter because older apps read one and newer ones read the other. Alongside it go the secret, the algorithm, the digit count and the period. Nothing in the URI is secret except the secret itself, which is the whole of it, so a screenshot of the QR code is as good as the credential.

What people use it for

  • Setting up two-factor authentication on a service you are building
  • Producing the secret and the otpauth URI an enrolment screen has to show
  • A throwaway secret for exercising a login flow’s second step in testing
  • Rotating a shared secret after a database dump
  • Checking what a valid otpauth URI looks like before writing the code that builds one
  • Seeding a test fixture that needs a stable second factor
  • Comparing your enrolment URI against a known-good one when an app refuses to scan it

Questions

RFC 4226 requires at least 128 bits and recommends 160. This generates 160, which is 32 base32 characters.

RFC 6238. TOTP: Time-Based One-Time Password AlgorithmRFC 4226. HOTP: An HMAC-Based One-Time Password Algorithm (the 128-bit minimum and 160-bit recommendation)RFC 4648. Base16, Base32 and Base64 data encodingsGoogle Authenticator, the otpauth Key URI format
Was this tool any good?
Internal signal only · I use it to find the tools worth rebuilding