Time-Based

Codes refresh every 30 seconds for maximum security.

Offline Capable

Works without internet connection on the user's device.

RFC 6238 Compliant

Compatible with any authenticator app.

TOTP Setup Flow

1

Generate a TOTP Secret

Create a unique secret for the user and store it securely.

// Generate TOTP secret for a user
const totp = await affirmid.totp.create({
  userId: 'user_123',
  issuer: 'Acme Inc',        // Your company name
  accountName: 'john@example.com'  // User identifier
});

console.log(totp);
// {
//   secret: 'JBSWY3DPEHPK3PXP',   // Base32 encoded secret
//   qrCodeUrl: 'data:image/png;base64,...',
//   otpauthUrl: 'otpauth://totp/Acme:john@example.com?...'
// }
2

Display QR Code to User

Show the QR code for the user to scan with their authenticator app.

// React component example
function TotpSetup({ qrCodeUrl, secret }) {
  return (
    <div>
      <h2>Scan this QR code with your authenticator app</h2>
      <img src={qrCodeUrl} alt="TOTP QR Code" />

      {/* Manual entry fallback */}
      <p>Or enter this code manually:</p>
      <code>{secret}</code>
    </div>
  );
}
3

Verify Initial Code

Confirm the user has set up their authenticator correctly before enabling TOTP.

// Verify the setup code
const verification = await affirmid.totp.verifySetup({
  userId: 'user_123',
  code: '123456'  // Code entered by user
});

if (verification.valid) {
  // TOTP is now active for this user
  console.log('TOTP enabled successfully');
} else {
  console.log('Invalid code, please try again');
}

Verifying TOTP Codes

Basic Verification

// Verify a TOTP code during login
async function verifyTotpLogin(userId: string, code: string) {
  const result = await affirmid.totp.verify({
    userId: userId,
    code: code
  });

  if (result.valid) {
    // Code is correct - grant access
    return { success: true };
  } else {
    // Invalid code
    return {
      success: false,
      error: result.reason  // 'invalid_code' | 'expired' | 'already_used'
    };
  }
}

With Replay Protection

AffirmID automatically prevents code reuse. Each code can only be used once within its validity window.

// Codes are automatically tracked
const result1 = await affirmid.totp.verify({ userId, code: '123456' });
console.log(result1.valid); // true

// Same code cannot be reused
const result2 = await affirmid.totp.verify({ userId, code: '123456' });
console.log(result2.valid);  // false
console.log(result2.reason); // 'already_used'

Configuration Options

OptionDefaultDescription
period30Seconds between code rotations
digits6Number of digits in the code
algorithmSHA1SHA1, SHA256, or SHA512
window1Number of periods to accept (before/after)

Backup Codes

Generate one-time backup codes for users who lose access to their authenticator app.

// Generate backup codes
const backupCodes = await affirmid.totp.generateBackupCodes({
  userId: 'user_123',
  count: 10  // Generate 10 codes
});

console.log(backupCodes);
// {
//   codes: ['ABCD-1234', 'EFGH-5678', ...],
//   createdAt: '2024-01-15T12:00:00Z'
// }

// Verify a backup code
const result = await affirmid.totp.verifyBackupCode({
  userId: 'user_123',
  code: 'ABCD-1234'
});
// Each backup code can only be used once

Important

Display backup codes only once during setup. Advise users to store them securely offline. Consider requiring re-authentication before generating new backup codes.

Best Practices

Verify during setup

Always verify the initial code before enabling TOTP.

Provide backup codes

Generate backup codes so users can recover access.

Show manual entry option

Some users can't scan QR codes - show the secret key.

Use as fallback

Offer TOTP when push notifications aren't available.

Related Guides