TOTP fundamentals — a beginner-friendly course
Time-based one-time passwords (TOTP) give your users a second factor that attackers cannot easily steal. This course walks from first principles to production roll-out so you can confidently add TOTP to any application. BatchToolkit's [TOTP Generator](/tools/totp-generator) helps you explore each concept safely in your browser.
Time-based one-time passwords (TOTP) give your users a second factor that attackers cannot easily steal. This course walks from first principles to production roll-out so you can confidently add TOTP to any application. BatchToolkit's TOTP Generator helps you explore each concept safely in your browser.
Learning while doing is powerful. Keep the generator open in another tab and recreate every example as you read.
- Why TOTP matters
- The building blocks of TOTP
- How the algorithm produces a code
- Hands-on: enroll your first user
- Hands-on: verify a submitted token
- Keeping clocks in sync
- Designing recovery and fallback options
- Shipping TOTP in real products
- Security guardrails and compliance
- Frequently asked questions
- Practice checklist
Why TOTP matters
- Stops password reuse attacks. Even if a password leaks, the attacker still needs the fresh 6-digit code that expires after 30 seconds.
- No proprietary hardware required. Authenticator apps (1Password, Google Authenticator, Authy, Microsoft Authenticator) run on phones, tablets, and browsers.
- Open standard. TOTP is defined in RFC 6238 and backed by the HMAC-based one-time password (HOTP) standard. Any compliant app can verify your tokens.
The building blocks of TOTP
TOTP extends HOTP by replacing an incrementing counter with the current time window.
- Shared secret: A random 160-bit (or longer) value encoded as base32. Both the server and authenticator app must store it securely.
- Timestep: The duration of each time window. RFC 6238 defaults to 30 seconds. Both sides derive the same counter value by dividing the current Unix timestamp by the timestep.
- Hash algorithm: Most deployments use HMAC-SHA1. Some organizations upgrade to SHA256 or SHA512 for higher entropy; the standard supports all three.
- Digits: The number of digits in the displayed one-time password—typically 6, sometimes 8 for high-security environments.
How the algorithm produces a code
- Calculate the moving factor.
counter = floor(currentUnixTime / timestep). - Generate HMAC.
hmac = HMAC(hashAlgorithm, secret, counter). The counter is an 8-byte big-endian integer. - Dynamic truncation. Use the lowest nibble of the last byte of
hmacas an offset, then read 4 bytes starting at that offset. - Convert to integer.
int = truncatedBytes & 0x7FFFFFFF(keep it positive). - Reduce to desired length.
code = int mod 10^digits. - Pad with zeros. Ensure the code has the required number of digits.
Authenticators and servers that follow the same steps will always generate the same result for the same time window.
Hands-on: enroll your first user
- Create a secret. Use BatchToolkit's generator or your backend to produce at least 20 bytes of randomness, then encode as base32.
- Build an otpauth URI. Format:
otpauth://totp/<Label>?secret=<Base32>&issuer=<Issuer>&digits=6&period=30. - Render a QR code. Display it only inside an authenticated session. If you use BatchToolkit, the QR code updates automatically when you change parameters.
- Collect a proof code. Ask the user to enter the current TOTP value to confirm setup. Only activate the second factor after this succeeds.
- Store securely. Persist the secret encrypted-at-rest. Hash backup codes and flag them with usage timestamps just like passwords.
UX tips
- Keep labels human-readable:
BatchToolkit:[email protected]. - Remind users to save backup codes before leaving the screen.
- Offer copy buttons for accessibility but never send the secret via email or chat.
Hands-on: verify a submitted token
- Recompute the counter. Use the server's current time to derive the
currentCounter. - Allow a window. Check
currentCounter,currentCounter - 1, andcurrentCounter + 1to tolerate ±30 seconds of drift. - Compare securely. Use constant-time comparison to avoid timing leaks.
- Throttle attempts. Lock the factor after repeated failures and trigger alerts.
- Log success and failure. Include device fingerprinting or IP evidence to support fraud investigations.
Many language libraries (otpauth for Node.js, pyotp for Python, oatpp/otp for Go, spomky-labs/otphp for PHP) already implement these steps. BatchToolkit's verification preview mirrors the same logic so you can sanity-check responses locally.
Keeping clocks in sync
- Sync servers: Enable NTP or systemd-timesyncd and monitor drift metrics. TOTP is only as reliable as your clock.
- Educate users: Suggest enabling "Set Automatically" on their devices. When they travel between timezones, authenticator apps follow the device clock.
- Expand window cautiously: If your audience frequently uses old phones, allow ±2 timesteps temporarily but combine with stricter rate limiting.
- Surface clock errors: If verification fails, display a hint like "Check your device time" before locking the account.
Designing recovery and fallback options
- Backup codes: Issue one-time strings (typically 8–10 characters) and display them once. Mark each as used when redeemed.
- Alternate factors: Offer WebAuthn, email links, or SMS as short-term fallbacks. Encourage users to re-enable TOTP afterward.
- Support channels: Train your support team to verify identity without bypassing security. Require at least two strong proofs before resetting TOTP.
- Secret rotation: If backup codes are used frequently or a support reset occurs, generate a fresh secret and require re-enrollment.
Shipping TOTP in real products
- Admin toggle: Add a switch for "Require TOTP" inside account settings, alongside status indicators (Enabled/Disabled/Pending verification).
- Policy enforcement: For privileged roles (admins, billing owners), enforce TOTP enrollment before granting access.
- CI / automation accounts: Store secrets in secret managers (AWS Secrets Manager, Vault, Doppler). Generate codes at runtime, never in source control.
- Events and analytics: Track enrollment rate, verification failures, and recovery events to identify friction points.
Security guardrails and compliance
- Encrypt secrets at rest using a dedicated key that rotates regularly. Limit decryption to minimal services.
- Mask codes in logs. Log attempts without exposing the actual OTP digits.
- Apply least privilege. Only the authentication service should access raw secrets.
- Compliance: TOTP helps satisfy MFA requirements in SOC 2, ISO 27001, PCI DSS, and HIPAA. Document the workflow in your control evidence.
Frequently asked questions
What happens if a user loses their device? Use backup codes or support-assisted identity verification to reset their factor and issue a new secret.
Can I change the timestep? You can, but authenticator apps must support it. Stick to 30 seconds unless you control both client and server.
Are 6 digits enough? Six digits give one million combinations. For public-facing apps this is acceptable with rate limiting. Consider 8 digits for internal or high-risk systems.
Why base32 for secrets? Base32 avoids visually ambiguous characters and is widely supported by authenticator apps.
Practice checklist
- Recreate the enrollment flow with the TOTP Generator and scan the QR code in your authenticator app.
- Write a small script (any language) that verifies the code using the same secret.
- Simulate clock drift by manually adjusting your system time and observing verification windows.
- Draft a support playbook handling lost device scenarios and backup code resupply.
- Audit your storage layer to confirm secrets and backup codes meet encryption and access-control standards.
Mastering these fundamentals ensures your users stay secure without sacrificing usability. Keep experimenting—you can always regenerate secrets inside BatchToolkit while you iterate on your rollout plan.