Implementing Two-Factor Authentication (2FA) with Claude Code
Learn about implementing two-factor authentication (2fa) using Claude Code. Includes practical code examples.
二要素認証をClaude Codeで実装する
アカウントのセキュリティを強化する二要素認証(2FA)は、現在のWebアプリケーションに欠かせない機能です。Claude Codeを使えば、TOTPベースの2FA、QRコード表示、バックアップコードを含む完全な実装を構築できます。
TOTPの仕組み
TOTP(Time-based One-Time Password)は、共有シークレットと現在時刻から30秒ごとに6桁のコードを生成するアルゴリズムです。Google AuthenticatorやAuthyなどのアプリで利用されています。
> TOTPベースの二要素認証を実装して。
> QRコード生成、有効化フロー、ログイン時の検証、
> バックアップコード10個の生成も含めて。
シークレット生成と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 {
// 2FA設定の開始(シークレットとQRコード生成)
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 };
}
// コードを検証して2FAを有効化
async enable(userId: string, token: string) {
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user?.twoFactorSecret) throw new Error('2FAが設定されていません');
const isValid = authenticator.verify({
token,
secret: user.twoFactorSecret,
});
if (!isValid) throw new Error('無効なコードです');
// バックアップコードを生成
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 }; // ユーザーに表示(一度だけ)
}
// ログイン時のコード検証
async verify(userId: string, token: string): Promise<boolean> {
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user?.twoFactorSecret) return false;
// TOTPコードで検証
const isValid = authenticator.verify({
token,
secret: user.twoFactorSecret,
});
if (isValid) return true;
// バックアップコードで検証
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
const codeIndex = user.backupCodes.indexOf(hashedToken);
if (codeIndex !== -1) {
// 使用済みのバックアップコードを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()
);
}
}
2FA設定画面
// 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桁のコードを入力"
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>
);
}
Verwandte Artikel
認証全般については認証機能の実装ガイド、パスワード関連はパスワードリセット実装も参考にしてください。
TOTPの仕様はRFC 6238で定義されています。
Related Posts
So beschleunigen Sie Ihre Nebenprojekte mit Claude Code [Mit Beispielen]
Erfahren Sie, wie Sie persönliche Entwicklungsprojekte mit Claude Code drastisch beschleunigen. Inklusive realer Beispiele und eines praktischen Workflows von der Idee bis zum Deployment.
So automatisieren Sie Refactoring mit Claude Code
Erfahren Sie, wie Sie Code-Refactoring mit Claude Code effizient automatisieren. Inklusive praktischer Prompts und konkreter Refactoring-Muster für reale Projekte.
Vollständiger CORS-Konfigurationsleitfaden mit Claude Code
Erfahren Sie alles über die CORS-Konfiguration mit Claude Code. Mit praktischen Tipps und Codebeispielen.