Back to 20 Concepts
oauth-oidcIntermediate

Time-Based One-Time Passwords (TOTP RFC 6238) & 30s Timesteps

TOTP computes dynamic 6-digit codes by taking a shared Base32 secret key and a 30-second epoch time counter (T = floor(UnixTime / 30)), hashing them with HMAC-SHA1 and performing 4-bit dynamic truncation.

Intuitive Mental Model

The Synchronized Atomic Watches: You and the bank both hold identical secret formulas and synchronized clocks. Every 30 seconds, both watches advance by 1 tick, computing the exact same 6-digit number without any network connection.

Architecture Blueprint & CodeProduction Standard
import { createHmac } from 'crypto';

function generateTOTP(secretBase32: string, timeStepSeconds = 30): string {
  const counter = Math.floor(Date.now() / 1000 / timeStepSeconds);
  const buffer = Buffer.alloc(8);
  buffer.writeBigInt64BE(BigInt(counter));
  
  const hmac = createHmac('sha1', base32Decode(secretBase32)).update(buffer).digest();
  const offset = hmac[hmac.length - 1] & 0xf;
  const code = (hmac.readUInt32BE(offset) & 0x7fffffff) % 1000000;
  return code.toString().padStart(6, '0');
}

Key Architectural Takeaways

  • Clock Drift Tolerance: Production servers verify code at T-1, T, and T+1 (±30 seconds) to account for client device clock skew.
  • Air-Gapped Operation: Works completely offline on mobile devices (Google Authenticator) with zero SMS/carrier interception risks.
Common Architectural Pitfall

Allowing the same 6-digit TOTP code to be used multiple times within its 30-second window (vulnerable to replay attacks).

Production Best Practice

Store used TOTP tokens in Redis for 60 seconds and reject duplicate attempts.