Use Cases

Claude Code के साथ Implementing Two-Factor Authentication (2FA)

Claude Code का उपयोग करके implementing two-factor authentication (2fa) सीखें। Practical code examples शामिल हैं।

二要素authenticationको Claude Code सेimplement करना

アカウントのsecurityを強化する二要素authentication(2FA)は、現在のWebapplicationに欠かせないfeatures है।Claude Code का उपयोग करके、TOTPベースの2FA、QRcodedisplay、backupcodeを含む完全なimplementation build किया जा सकता है。

TOTPの仕組み

TOTP(Time-based One-Time Password)は、共有シークレットと現在時刻 से30秒ごとに6桁のcode generateするアルゴリズム है।Google AuthenticatorやAuthy आदिのアプリで利用されてい है।

> TOTPベースの二要素authenticationをimplement करो。
> QRcodegenerate、有効化フロー、logイン時の検証、
> backupcode10個のgenerateも含めて。

シークレットgenerateとQRcode

// src/lib/two-factor.ts
import { authenticator } from 'otplib';
import QRCode from 'qrcode';
import crypto from 'crypto';
import { prisma } from './prisma';

export class TwoFactorService {
  // 2FAsettingsの開始(シークレットとQRcodegenerate)
  async setup(userId: string) {
    const secret = authenticator.generateSecret();
    const user = await prisma.user.findUnique({ where: { id: userId } });

    const otpauthUrl = authenticator.keyuri(
      user!.email,
      'MyApp',
      secret
    );

    const qrCodeDataUrl = await QRCode.toDataURL(otpauthUrl);

    // シークレットを一時保存(まだ有効化しない)
    await prisma.user.update({
      where: { id: userId },
      data: { twoFactorSecret: secret, twoFactorEnabled: false },
    });

    return { qrCodeDataUrl, secret };
  }

  // codeを検証して2FAを有効化
  async enable(userId: string, token: string) {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user?.twoFactorSecret) throw new Error('2FAがsettingsされていません');

    const isValid = authenticator.verify({
      token,
      secret: user.twoFactorSecret,
    });

    if (!isValid) throw new Error('無効なcodeです');

    // backupcode generate
    const backupCodes = this.generateBackupCodes();
    const hashedCodes = backupCodes.map((code) =>
      crypto.createHash('sha256').update(code).digest('hex')
    );

    await prisma.user.update({
      where: { id: userId },
      data: {
        twoFactorEnabled: true,
        backupCodes: hashedCodes,
      },
    });

    return { backupCodes }; // userにdisplay(一度だけ)
  }

  // logイン時のcode検証
  async verify(userId: string, token: string): Promise<boolean> {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user?.twoFactorSecret) return false;

    // TOTPcodeで検証
    const isValid = authenticator.verify({
      token,
      secret: user.twoFactorSecret,
    });

    if (isValid) return true;

    // backupcodeで検証
    const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
    const codeIndex = user.backupCodes.indexOf(hashedToken);
    if (codeIndex !== -1) {
      // 使用済みのbackupcodeをDelete
      const updatedCodes = [...user.backupCodes];
      updatedCodes.splice(codeIndex, 1);
      await prisma.user.update({
        where: { id: userId },
        data: { backupCodes: updatedCodes },
      });
      return true;
    }

    return false;
  }

  private generateBackupCodes(count = 10): string[] {
    return Array.from({ length: count }, () =>
      crypto.randomBytes(4).toString('hex').toUpperCase()
    );
  }
}

2FAsettings画面

// src/components/TwoFactorSetup.tsx
'use client';
import { useState } from 'react';

export function TwoFactorSetup() {
  const [step, setStep] = useState<'idle' | 'qr' | 'verify' | 'backup'>('idle');
  const [qrCode, setQrCode] = useState('');
  const [token, setToken] = useState('');
  const [backupCodes, setBackupCodes] = useState<string[]>([]);

  const startSetup = async () => {
    const res = await fetch('/api/user/2fa/setup', { method: 'POST' });
    const data = await res.json();
    setQrCode(data.qrCodeDataUrl);
    setStep('qr');
  };

  const verifyAndEnable = async () => {
    const res = await fetch('/api/user/2fa/enable', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token }),
    });
    const data = await res.json();
    setBackupCodes(data.backupCodes);
    setStep('backup');
  };

  if (step === 'idle') {
    return (
      <button onClick={startSetup} className="bg-blue-600 text-white px-6 py-2 rounded-lg">
        二要素authenticationをsettingsする
      </button>
    );
  }

  if (step === 'qr') {
    return (
      <div className="space-y-4">
        <p className="dark:text-gray-300">authenticationアプリでQRcodeをスキャンしてください</p>
        <img src={qrCode} alt="QRcode" className="mx-auto" />
        <input
          value={token}
          onChange={(e) => setToken(e.target.value)}
          placeholder="6桁のcodeを入力"
          className="w-full border rounded px-3 py-2"
          maxLength={6}
        />
        <button onClick={verifyAndEnable} className="bg-blue-600 text-white px-6 py-2 rounded-lg w-full">
          confirmして有効化
        </button>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <h3 className="font-bold text-green-600">二要素authenticationが有効になりました</h3>
      <p className="text-sm text-gray-600 dark:text-gray-400">
        निम्नलिखितのbackupcodeをsafeな場所に保存して करें।各codeは一度だけ使え है।
      </p>
      <div className="grid grid-cols-2 gap-2 bg-gray-50 dark:bg-gray-800 p-4 rounded-lg font-mono text-sm">
        {backupCodes.map((code, i) => (
          <span key={i} className="dark:text-gray-300">{code}</span>
        ))}
      </div>
    </div>
  );
}

関連記事

authentication全般के बारे मेंはauthenticationfeaturesのimplementationガイド、pathワード関連はpathワードリセットimplementationभी reference के लिए देखें。

TOTPの仕様はRFC 6238で定義されてい है।

#Claude Code #two-factor auth #2FA #TOTP #security