Skip to content

Instantly share code, notes, and snippets.

@aravindkumarsvg
Last active June 16, 2025 16:49
Show Gist options
  • Save aravindkumarsvg/709e9e8e101313cd20cfe32dc9634438 to your computer and use it in GitHub Desktop.
Save aravindkumarsvg/709e9e8e101313cd20cfe32dc9634438 to your computer and use it in GitHub Desktop.
TOTP Complete Guide

πŸ” TOTP (Time-Based One-Time Password) - Full Guide

πŸ“˜ What is TOTP?

TOTP (Time-Based One-Time Password) is a one-time password algorithm that uses the current time as a variable. It is commonly used in two-factor authentication (2FA) systems. TOTP generates a numeric code that changes every 30 seconds and is based on a shared secret between the client and the server.

  • Defined in RFC 6238
  • Based on HOTP (HMAC-based One-Time Password, RFC 4226)

πŸ§ͺ How TOTP Works

  1. Shared Secret: A Base32-encoded key is shared between the server and the client (user).
  2. Time Counter: Unix time is divided by a fixed interval (usually 30 seconds) to get a moving counter.
    counter = floor(current_unix_time / time_step)
    
  3. HMAC Generation: HMAC-SHA1 is applied using the shared secret and the counter.
  4. Dynamic Truncation: Extracts a 4-byte dynamic binary code from the HMAC result.
  5. Modulo Operation: Converts to a 6-digit code using modulo:
    OTP = (truncated_value) % 10^6
    

πŸ”— TOTP Auth URL Format (otpauth://)

TOTP secrets can be encoded into a URL and represented as a QR code for use in authenticator apps.

otpauth://totp/{ISSUER}:{ACCOUNT}?secret={SECRET}&issuer={ISSUER}&digits=6&period=30

Example:

otpauth://totp/DevApp:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=DevApp
  • issuer: Name of the service or app (URL-safe)
  • account: Typically user's email or username
  • secret: Shared secret (Base32-encoded)
  • digits: Number of digits in the TOTP (default is 6)
  • period: Time step duration in seconds (default is 30)

πŸ“² Authenticator App Integration

Supported Apps

  • Google Authenticator
  • Microsoft Authenticator
  • Authy
  • 1Password
  • FreeOTP
  • Aegis (Android)

Workflow

  1. Server generates a shared secret and encodes it in a TOTP URI.
  2. User scans the QR code containing the URI using an authenticator app.
  3. App generates a new TOTP code every 30 seconds.
  4. User enters the code during authentication.
  5. Server verifies the TOTP code using the shared secret and current time.

πŸ“Έ Generating a TOTP QR Code

Using Python

import pyotp
import qrcode

totp = pyotp.TOTP("JBSWY3DPEHPK3PXP")
uri = totp.provisioning_uri(name="[email protected]", issuer_name="DevApp")

# Generate QR code image
img = qrcode.make(uri)
img.save("totp_qr.png")

Using CLI (Linux/macOS)

qrencode -o totp.png "otpauth://totp/DevApp:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=DevApp"

πŸ” Validating TOTP on the Server

Python (with pyotp)

import pyotp

totp = pyotp.TOTP("JBSWY3DPEHPK3PXP")
if totp.verify("123456"):
    print("βœ… Token is valid")
else:
    print("❌ Invalid token")

Node.js (with speakeasy)

const speakeasy = require("speakeasy");

const verified = speakeasy.totp.verify({
  secret: "JBSWY3DPEHPK3PXP",
  encoding: "base32",
  token: "123456",
  window: 1 // allows +/- 1 time step
});

console.log(verified ? "βœ… Token is valid" : "❌ Invalid token");

⏱️ Time Skew Handling

To tolerate slight clock differences between server and client, a window parameter is used:

  • window = 1 allows one time-step before and after the current time.

Examples:

  • pyotp.TOTP(...).verify(token, valid_window=1)
  • speakeasy.totp.verify({ ..., window: 1 })

⏱️ TOTP Token Validity: Why Codes Work After 30 Seconds

πŸ“± Observation

Even though Google Authenticator shows a 30-second countdown, the same TOTP code may still be accepted by the server after the timer resets. This is due to a concept called time window (or skew tolerance).


πŸ” How TOTP Time Window Works

TOTP tokens are generated based on time intervals:

TOTP = HMAC(secret, floor(current_unix_time / 30))

But due to potential clock skew between the client (user device) and the server, most implementations allow a small time window around the current 30-second step:

  • T - 1 β†’ previous time step (up to 30 seconds before)
  • T β†’ current time step (30 seconds)
  • T + 1 β†’ next time step (up to 30 seconds after)

⏳ Total Valid Time:

A code may be valid for up to 90 seconds if the server allows a Β±1 window.


πŸ§ͺ Example in Node.js (speakeasy)

speakeasy.totp.verify({
  secret: user.secret,
  encoding: 'base32',
  token: '123456',
  window: 1  // Allows current, previous, and next time steps
});

If you want to make tokens valid for only 30 seconds:

window: 0

But this is not recommended in real-world apps due to:

  • Minor time drift between server and client
  • Network delay

βœ… Best Practice

Scenario Recommended window
Production Login Flow 1 (Β±30s tolerance)
High-Security Operation 0 (strict match)
Debugging 1 or higher

πŸ›  Tip: Check Clock Drift

To ensure better accuracy, synchronize your server clock using NTP (Network Time Protocol) services. If needed, compare client and server timestamps during debugging.


πŸ›‘οΈ Security Best Practices

  • πŸ”’ Store shared secrets securely (use KMS, encrypted storage)
  • ⚠️ Never log TOTP secrets or OTP codes
  • 🚫 Don't transmit secrets in clear text
  • πŸ•“ Use secure time synchronization on both server and client
  • πŸ“› Rotate secrets when a device is lost or reset
  • πŸ” Implement retry limits and lockout policies
  • βœ… Always enforce HTTPS for QR provisioning and verification endpoints

πŸ§ͺ Tools for Development and Testing

Tool Purpose
pyotp TOTP generation/verification (Python)
speakeasy TOTP/HOTP support (Node.js)
qrcode Generate QR codes in Python
qrencode Generate QR codes via CLI
Aegis/Authy Mobile apps for testing TOTP

πŸ” TOTP Backup Codes: Are They Required?

βœ… Short Answer

Yes β€” TOTP backup codes are strongly recommended, even though they are not part of the TOTP standard itself.


πŸ“Œ Why Are Backup Codes Important?

TOTP is tied to a shared secret stored in an authenticator app. If you:

  • Lose your phone
  • Reset or uninstall the app
  • Upgrade devices without exporting TOTP secrets

πŸ‘‰ You lose access to your account unless:

  • You exported the secret key beforehand
  • OR you have backup codes

πŸ”„ What Are Backup Codes?

  • One-time use codes
  • Typically 8–12 characters long
  • Provided when setting up TOTP
  • Can be used as a fallback when you can’t access your authenticator app

🧾 Example:

Your backup codes:
1. 4KJF-2D8A
2. XZPR-7A9T
3. 9QWE-LM4Z
...
(Each code can be used only once)

πŸ§ͺ How Backup Codes Work

  1. User sets up TOTP 2FA
  2. Server generates a list of backup codes
  3. User saves these codes securely
  4. If TOTP is unavailable:
    • User selects β€œUse backup code”
    • Enters one of the unused codes
    • The code is validated and marked as used

πŸ›‘οΈ Security Practices

Practice Recommendation
Generate only once (or reset) βœ… Yes
Allow regeneration (invalidate old) βœ… Yes
Store as hashes (not plaintext) βœ… Yes
Limit attempts per code/login βœ… Yes
Display/download securely βœ… Yes

🧩 Alternatives and Additions

Recovery Method Security Level Usability
Backup Codes βœ… High βœ… Easy
SMS fallback ❌ Low βœ… Easy
Email-based recovery ❌ Medium βœ… Medium
Recovery key (manual) βœ… High ⚠️ Manual
Device-based recovery βœ… High βœ… Medium

βœ… Conclusion

While not mandatory in TOTP specs, backup codes are a critical recovery tool to prevent users from getting locked out of their accounts. They also reduce helpdesk load and improve user experience in secure environments.


πŸ“š References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment