Two-factor authentication (2FA) dramatically reduces account takeovers — even if an attacker has your user's password, they can't log in without the second factor. TOTP (Time-based One-Time Password) is the gold standard for developer-built 2FA: no SMS required, works offline, compatible with Google Authenticator, Authy, 1Password, and every major authenticator app.
This guide covers how TOTP works mathematically, how to implement it in a Next.js app, and common pitfalls to avoid.
How TOTP Works (The Short Version)
TOTP is defined in RFC 6238. The algorithm is surprisingly simple:
- Server and authenticator app share a secret key (a 20-byte random string, encoded as base32)
- Both compute:
HOTP(secret, floor(currentTime / 30))— the time counter steps every 30 seconds - HOTP uses HMAC-SHA1 to generate a 6-digit code from the secret + counter
- Server accepts codes from the current window ± 1 (±30 seconds) to account for clock skew
Because both sides independently compute the same value from a shared secret and the current time, no code is ever transmitted during verification — it's just computed locally and compared.
// The math behind a TOTP code (simplified)
const counter = Math.floor(Date.now() / 1000 / 30);
const hmac = createHmac("sha1", secret).update(toBuffer(counter)).digest();
const offset = hmac[hmac.length - 1] & 0xf;
const code = (
((hmac[offset] & 0x7f) << 24) |
((hmac[offset + 1] & 0xff) << 16) |
((hmac[offset + 2] & 0xff) << 8) |
(hmac[offset + 3] & 0xff)
) % 1_000_000;
// → 6-digit code, changes every 30 secondsTOTP vs SMS 2FA
| Factor | TOTP | SMS OTP |
|---|---|---|
| SIM swap attack | Not vulnerable | Vulnerable |
| Works offline | Yes | No |
| Cost | Free | ~$0.01–0.05 per SMS |
| Setup friction | Medium (scan QR code) | Low (enter phone number) |
| Phishing resistance | High | Medium |
| Adoption rate (B2B) | High | Medium |
SMS 2FA is better than nothing, but TOTP is meaningfully more secure. SS7 vulnerabilities and SIM swap attacks have led to high-profile account takeovers at major companies. For any app handling sensitive data, TOTP should be your 2FA method of choice.
Implementing TOTP with Vaultix-ID
Step 1: Enroll the user
// Call the TOTP enrollment endpoint — returns a QR code URL and backup codes
const res = await fetch(`${apiBase}/v1/me/totp/enroll`, {
method: "POST",
headers: { "Cookie": sessionCookie },
});
const { qrCodeUrl, backupCodes, secret } = await res.json();
// Render the QR code — user scans with Authenticator app
<img src={qrCodeUrl} alt="Scan with your authenticator app" />Step 2: Verify and activate
// User enters the 6-digit code from their app to confirm setup
const res = await fetch(`${apiBase}/v1/me/totp/verify`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Cookie": sessionCookie,
},
body: JSON.stringify({ code: "123456" }),
});
if (res.ok) {
// TOTP is now active on the account
// Future sign-ins will require the TOTP code
}Step 3: Prompt during sign-in
// If a user has TOTP enabled, the sign-in response returns:
// { requiresMfa: true, mfaToken: "temp_token_xyz" }
// The client then shows a TOTP prompt:
const mfaRes = await fetch(`${apiBase}/v1/sign-in/mfa`, {
method: "POST",
body: JSON.stringify({
mfaToken: "temp_token_xyz",
code: userEnteredCode,
strategy: "totp",
}),
});
// On success: session cookie is set and user is fully authenticatedSecurity Checklist for TOTP
- Generate secrets with a CSPRNG: use
crypto.randomBytes(20)in Node.js — neverMath.random() - Encrypt secrets at rest: TOTP secrets should be AES-256 encrypted in your database (Vaultix-ID does this automatically)
- Rate-limit code attempts: max 3 attempts per token, 5-minute lockout on failure
- Prevent replay attacks: mark each validated code as used within its 30-second window
- Backup codes: always generate 8–10 single-use backup codes at enrollment time and store them hashed
- Clock skew tolerance: accept codes from ±1 window (±30 seconds) but not more
Vaultix-ID handles all of this out of the box: CSPRNG secrets, AES-256 encryption, rate limiting on OTP attempts, replay prevention, and backup code generation.
Conclusion
TOTP is the right 2FA method for most applications. It's free, offline-capable, phishing-resistant, and supported by every major authenticator app. The implementation is well-understood and the security properties are strong when done correctly. Add TOTP MFA to your app today with Vaultix-ID — it's one API call to enroll and one to verify.