Use Cases

Mengimplementasikan Two-Factor Authentication (2FA) dengan Claude Code

Learn about implementing two-factor authentication (2fa) using Claude Code. Includes practical code examples.

二elemen認証 dengan Claude Code: implementasi

アカウント セキュリティ 強化 二elemen認証(2FA) 、現在 Webaplikasi 欠かせ tidak機能.Claude Code 使えば、TOTPベース 2FA、QRコードtampilan、バックアップコード 含む完全なimplementasi pembangunan bisa dilakukan.

mekanisme TOTP

TOTP(Time-based One-Time Password) 、berbagiシークレット dan 現在時刻 dari 30秒ご dan 6桁 コード generate algoritma.Google AuthenticatorやAuthy dll. aplikasi pemanfaatanされてい.

> TOTPベース 二elemen認証 implementasikan.
> QRコードgenerate、efektif化フロー、login時 verifikasi、
> バックアップコード10個 generate juga 含めて。

シークレットgenerateとQRコード

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

export class TwoFactorService {
  // 2FApengaturan mulai(シークレット dan QRコードgenerate)
  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);

    // シークレット 一時penyimpanan(まだefektif化し tidak)
    await prisma.user.update({
      where: { id: userId },
      data: { twoFactorSecret: secret, twoFactorEnabled: false },
    });

    return { qrCodeDataUrl, secret };
  }

  // コード verifikasi 2FA efektif化
  async enable(userId: string, token: string) {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user?.twoFactorSecret) throw new Error('2FA pengaturanされていません');

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

    if (!isValid) throw new Error('無効なコード す');

    // バックアップコード 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 }; // pengguna tampilan(一度だけ)
  }

  // login時 コードverifikasi
  async verify(userId: string, token: string): Promise<boolean> {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user?.twoFactorSecret) return false;

    // TOTPコード verifikasi
    const isValid = authenticator.verify({
      token,
      secret: user.twoFactorSecret,
    });

    if (isValid) return true;

    // バックアップコード verifikasi
    const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
    const codeIndex = user.backupCodes.indexOf(hashedToken);
    if (codeIndex !== -1) {
      // penggunaan済み バックアップコード 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()
    );
  }
}

2FApengaturan画面

// 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">
        二要素認証を設定する
      </button>
    );
  }

  if (step === 'qr') {
    return (
      <div className="space-y-4">
        <p className="dark:text-gray-300">認証アプリでQRコードをスキャンしてください</p>
        <img src={qrCode} alt="QRコード" className="mx-auto" />
        <input
          value={token}
          onChange={(e) => setToken(e.target.value)}
          placeholder="6桁 コード input"
          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">
          確認して有効化
        </button>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <h3 className="font-bold text-green-600">二要素認証が有効になりました</h3>
      <p className="text-sm text-gray-600 dark:text-gray-400">
        以下のバックアップコードを安全な場所に保存してください。各コードは一度だけ使えます。
      </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>
  );
}

Artikel Terkait

認証全般 mengenai 認証機能 implementasipanduan、パスワード関連 パスワードリセットimplementasi juga bisa dijadikan referensi.

TOTP 仕様 RFC 6238 definisiされてい.

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