Implementing Two-Factor Authentication (2FA): Claude Code 활용 가이드
implementing two-factor authentication (2fa): Claude Code 활용. 실용적인 코드 예시를 포함합니다.
二要素인증を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>
);
}
関連글
인증全般에 대해서는인증機能の구현가이드、비밀번호関連は비밀번호리셋구현도 참고하세요.
TOTP의 사양은RFC 6238で定義されています。
#Claude Code
#two-factor auth
#2FA
#TOTP
#security
Related Posts
Use Cases
Use Cases
Claude Code로 리팩토링을 자동화하는 방법
Claude Code를 활용해 코드 리팩토링을 효율적으로 자동화하는 방법을 알아봅니다. 실전 프롬프트와 구체적인 리팩토링 패턴을 소개합니다.
Use Cases
Use Cases
Claude Code로 사이드 프로젝트 개발 속도를 극대화하는 방법 [예제 포함]
Claude Code를 활용해 개인 프로젝트 개발 속도를 획기적으로 높이는 방법을 알아봅니다. 실전 예제와 아이디어부터 배포까지의 워크플로를 포함합니다.
Use Cases
Use Cases
Complete CORS Configuration Guide: Claude Code 활용 가이드
complete cors configuration guide: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.