[TERMINAL · SKILLS]
> mounting /skills...
> indexing 295 manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Terminal.skills
Use Cases/Build a Two-Factor Authentication System

Build a Two-Factor Authentication System

Build a complete 2FA system with TOTP (Google Authenticator), backup codes, SMS fallback, device trust, and account recovery — hardening user accounts against credential theft.

#redis#caching#database#pub-sub#queues
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 5 skills

Avg quality 93/100·All SAFE
>

typescript

v

Not yet scored
View skill
>

redis

v1.0.0

Build applications with Redis — caching, session storage, pub/sub, streams, rate limiting, leaderboards, and queues. Use when tasks involve in-memory data storage, real-time messaging, distributed locking, or performance optimization with caching layers.

93/100 quality
1.81× impact
SAFE
View skill
>

postgresql

v1.0.0

Assists with designing schemas, writing performant queries, managing indexes, and operating PostgreSQL databases. Use when working with JSONB, full-text search, window functions, CTEs, row-level security, replication, or performance tuning. Trigger words: postgresql, postgres, sql, database, jsonb, rls, window functions, cte.

87/100 quality
1.53× impact
SAFE
View skill
>

hono

v1.0.0

You are an expert in Hono, the ultrafast web framework for the edge. You help developers build APIs and web applications that run on Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda, and Vercel Edge — with a tiny footprint (~14KB), middleware ecosystem, JSX support, RPC client, and Web Standards API compatibility that makes code truly portable across runtimes.

93/100 quality
3.00× impact
SAFE
View skill
>

zod

v1.0.0

You are an expert in Zod, the TypeScript-first schema declaration and validation library. You help developers define schemas that validate data at runtime AND infer TypeScript types at compile time — eliminating the need to write types and validators separately. Used for API input validation, form validation, environment variables, config files, and any data boundary.

100/100 quality
1.21× impact
SAFE
View skill
$

The Problem

Lena leads security at a 30-person SaaS handling financial data. Three customer accounts were compromised last month through credential stuffing — attackers used leaked passwords from other sites. The company's security audit flagged "no multi-factor authentication" as a critical risk. Enterprise customers are requiring 2FA before signing contracts worth $200K/year. They need TOTP-based 2FA with backup codes, trusted device management, and an enrollment flow that doesn't frustrate users.

Step 1: Build the 2FA Engine

typescript
// src/auth/two-factor.ts — TOTP 2FA with backup codes and device trust
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
import { pool } from "../db";
import { Redis } from "ioredis";
import { z } from "zod";

const redis = new Redis(process.env.REDIS_URL!);

const TOTP_PERIOD = 30;            // seconds
const TOTP_DIGITS = 6;
const TOTP_WINDOW = 1;             // allow ±1 period for clock skew
const BACKUP_CODE_COUNT = 10;
const DEVICE_TRUST_DAYS = 30;

// Generate TOTP secret for enrollment
export async function initEnrollment(userId: string): Promise<{
  secret: string;
  otpauthUrl: string;
  qrDataUrl: string;
  backupCodes: string[];
}> {
  // Generate 20-byte secret (160 bits, RFC 4226 recommended)
  const secretBytes = randomBytes(20);
  const secret = base32Encode(secretBytes);

  // Get user info for the QR label
  const { rows: [user] } = await pool.query("SELECT email FROM users WHERE id = $1", [userId]);

  const issuer = "YourApp";
  const otpauthUrl = `otpauth://totp/${encodeURIComponent(issuer)}:${encodeURIComponent(user.email)}?secret=${secret}&issuer=${encodeURIComponent(issuer)}&digits=${TOTP_DIGITS}&period=${TOTP_PERIOD}`;

  // Generate backup codes
  const backupCodes = Array.from({ length: BACKUP_CODE_COUNT }, () =>
    randomBytes(4).toString("hex").match(/.{4}/g)!.join("-")   // format: a1b2-c3d4
  );

  // Store temporarily until user confirms with a valid code
  await redis.setex(`2fa:enroll:${userId}`, 600, JSON.stringify({
    secret,
    backupCodes,
  }));

  return {
    secret,
    otpauthUrl,
    qrDataUrl: otpauthUrl,     // frontend generates QR from this URL
    backupCodes,
  };
}

// Confirm enrollment by verifying user can generate valid codes
export async function confirmEnrollment(userId: string, code: string): Promise<boolean> {
  const enrollData = await redis.get(`2fa:enroll:${userId}`);
  if (!enrollData) throw new Error("Enrollment expired — start again");

  const { secret, backupCodes } = JSON.parse(enrollData);

  // Verify the code
  if (!verifyTOTP(secret, code)) {
    return false;
  }

  // Hash backup codes before storing
  const hashedBackupCodes = backupCodes.map((bc: string) =>
    createHmac("sha256", process.env.BACKUP_CODE_KEY!).update(bc).digest("hex")
  );

  // Save 2FA config
  await pool.query(
    `UPDATE users SET
       totp_secret = $2,
       totp_enabled = true,
       totp_backup_codes = $3,
       totp_enabled_at = NOW()
     WHERE id = $1`,
    [userId, encrypt(secret), JSON.stringify(hashedBackupCodes)]
  );

  await redis.del(`2fa:enroll:${userId}`);
  return true;
}

// Verify a TOTP code during login
export async function verifyCode(
  userId: string,
  code: string,
  deviceFingerprint?: string
): Promise<{ valid: boolean; deviceTrusted: boolean }> {
  // Check if device is trusted
  if (deviceFingerprint) {
    const trusted = await redis.get(`2fa:trust:${userId}:${deviceFingerprint}`);
    if (trusted) return { valid: true, deviceTrusted: true };
  }

  const { rows: [user] } = await pool.query(
    "SELECT totp_secret, totp_backup_codes FROM users WHERE id = $1 AND totp_enabled = true",
    [userId]
  );
  if (!user) throw new Error("2FA not enabled");

  const secret = decrypt(user.totp_secret);

  // Try TOTP first
  if (verifyTOTP(secret, code)) {
    // Prevent code reuse (replay attack)
    const replayKey = `2fa:used:${userId}:${code}`;
    const wasUsed = await redis.set(replayKey, "1", "EX", TOTP_PERIOD * 2, "NX");
    if (!wasUsed) return { valid: false, deviceTrusted: false };

    return { valid: true, deviceTrusted: false };
  }

  // Try backup code
  const normalizedCode = code.toLowerCase().replace(/\s/g, "");
  const codeHash = createHmac("sha256", process.env.BACKUP_CODE_KEY!).update(normalizedCode).digest("hex");
  const backupCodes: string[] = JSON.parse(user.totp_backup_codes);
  const codeIndex = backupCodes.indexOf(codeHash);

  if (codeIndex !== -1) {
    // Remove used backup code
    backupCodes.splice(codeIndex, 1);
    await pool.query("UPDATE users SET totp_backup_codes = $2 WHERE id = $1", [userId, JSON.stringify(backupCodes)]);

    // Warn if running low on backup codes
    if (backupCodes.length <= 2) {
      await redis.rpush("email:queue", JSON.stringify({
        type: "backup_codes_low",
        userId,
        remaining: backupCodes.length,
      }));
    }

    return { valid: true, deviceTrusted: false };
  }

  return { valid: false, deviceTrusted: false };
}

// Trust a device for 30 days (skip 2FA on this device)
export async function trustDevice(userId: string, deviceFingerprint: string): Promise<void> {
  await redis.setex(
    `2fa:trust:${userId}:${deviceFingerprint}`,
    86400 * DEVICE_TRUST_DAYS,
    new Date().toISOString()
  );

  // Track trusted devices
  await pool.query(
    `INSERT INTO trusted_devices (user_id, fingerprint, trusted_at, expires_at)
     VALUES ($1, $2, NOW(), NOW() + interval '30 days')
     ON CONFLICT (user_id, fingerprint) DO UPDATE SET trusted_at = NOW(), expires_at = NOW() + interval '30 days'`,
    [userId, deviceFingerprint]
  );
}

// TOTP implementation (RFC 6238)
function verifyTOTP(secret: string, code: string): boolean {
  const secretBytes = base32Decode(secret);
  const now = Math.floor(Date.now() / 1000);

  for (let i = -TOTP_WINDOW; i <= TOTP_WINDOW; i++) {
    const counter = Math.floor((now + i * TOTP_PERIOD) / TOTP_PERIOD);
    const expected = generateHOTP(secretBytes, counter);
    if (timingSafeEqual(Buffer.from(code), Buffer.from(expected))) {
      return true;
    }
  }
  return false;
}

function generateHOTP(secret: Buffer, counter: number): string {
  const buffer = Buffer.alloc(8);
  buffer.writeBigInt64BE(BigInt(counter));

  const hmac = createHmac("sha1", secret).update(buffer).digest();
  const offset = hmac[hmac.length - 1] & 0x0f;
  const binary =
    ((hmac[offset] & 0x7f) << 24) |
    ((hmac[offset + 1] & 0xff) << 16) |
    ((hmac[offset + 2] & 0xff) << 8) |
    (hmac[offset + 3] & 0xff);

  return (binary % 10 ** TOTP_DIGITS).toString().padStart(TOTP_DIGITS, "0");
}

function base32Encode(buffer: Buffer): string {
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  let result = "";
  let bits = 0, value = 0;
  for (const byte of buffer) {
    value = (value << 8) | byte;
    bits += 8;
    while (bits >= 5) {
      bits -= 5;
      result += alphabet[(value >> bits) & 0x1f];
    }
  }
  if (bits > 0) result += alphabet[(value << (5 - bits)) & 0x1f];
  return result;
}

function base32Decode(str: string): Buffer {
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  let bits = 0, value = 0;
  const output: number[] = [];
  for (const c of str.toUpperCase()) {
    const idx = alphabet.indexOf(c);
    if (idx === -1) continue;
    value = (value << 5) | idx;
    bits += 5;
    if (bits >= 8) { bits -= 8; output.push((value >> bits) & 0xff); }
  }
  return Buffer.from(output);
}

function encrypt(text: string): string { return text; /* use AES-256-GCM in production */ }
function decrypt(text: string): string { return text; }

Results

  • Account takeover incidents: 3/month → 0 — even with stolen passwords, attackers can't pass the TOTP step; credential stuffing attacks became ineffective
  • Enterprise deal closed: $200K/year — 2FA checkbox in the security questionnaire is now "yes"; compliance requirement met
  • User friction minimized — "trust this device" skips 2FA for 30 days on known devices; daily users enter a code once a month
  • Backup codes prevent lockout — 10 single-use codes generated at enrollment; users who lose their phone can still access their account
  • Replay attacks blocked — each TOTP code can only be used once within its time window; intercepted codes are useless