Claude Code के साथ Implementing Password Reset
Claude Code का उपयोग करके implementing password reset सीखें। Practical code examples शामिल हैं।
pathワードリセットfeaturesको Claude Code सेimplement करना
pathワードリセットはほぼसभीのWebアプリにज़रूरीなfeaturesですが、securityऊपरの落とし穴もज़्यादा領域 है।Claude Code का उपयोग करके、tokenのsafeなgenerate・検証、レート制限、メール送信を含むrobustなimplementation build किया जा सकता है。
リセットフローの全体像
- userがメールアドレスを入力
- serverがリセットtoken generateしメール送信
- userがメール内のlinkをクリック
- नयाpathワードを入力してupdate
> セキュアなpathワードリセットfeaturesをimplement करो。
> tokenの有効期限は1時बीच、使用は1回のみ。
> レート制限とメール送信も含めて。
tokengenerateとメール送信
// src/services/password-reset.ts
import crypto from 'crypto';
import bcrypt from 'bcryptjs';
import { prisma } from '@/lib/prisma';
import { sendEmail } from '@/lib/email';
export class PasswordResetService {
private static TOKEN_EXPIRY_HOURS = 1;
async requestReset(email: string) {
const user = await prisma.user.findUnique({ where: { email } });
// userが存在しなくてもsameresponseを返す(情報漏洩防止)
if (!user) return { success: true };
// レート制限: 同一メールへの送信は5分に1回 तक
const recentRequest = await prisma.passwordReset.findFirst({
where: {
userId: user.id,
createdAt: { gt: new Date(Date.now() - 5 * 60 * 1000) },
},
});
if (recentRequest) return { success: true };
// セキュアなtokengenerate
const token = crypto.randomBytes(32).toString('hex');
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
// पुरानाtokenをDelete
await prisma.passwordReset.deleteMany({ where: { userId: user.id } });
// नयाtokenを保存
await prisma.passwordReset.create({
data: {
userId: user.id,
token: hashedToken,
expiresAt: new Date(
Date.now() + this.constructor.TOKEN_EXPIRY_HOURS * 60 * 60 * 1000
),
},
});
// リセットメール送信
const resetUrl = `${process.env.APP_URL}/reset-password?token=${token}`;
await sendEmail({
to: email,
subject: 'pathワードリセットのご案内',
html: `
<h2>pathワードリセット</h2>
<p>निम्नलिखितのlinkをクリックしてpathワードをリセットして करें।</p>
<a href="${resetUrl}" style="display:inline-block;background:#3B82F6;color:#fff;padding:12px 24px;border-radius:8px;text-decoration:none;">
pathワードをリセット
</a>
<p style="color:#666;font-size:14px;margin-top:16px;">
इसlinkは1時बीचで有効期限が切れ है।<br />
心当たりがないcase में、इसメールを無視して करें।
</p>
`,
});
return { success: true };
}
async resetPassword(token: string, newPassword: string) {
const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
const resetRecord = await prisma.passwordReset.findFirst({
where: {
token: hashedToken,
expiresAt: { gt: new Date() },
used: false,
},
});
if (!resetRecord) {
throw new Error('無効または期限切れのtokenです');
}
// pathワードのvalidation
if (newPassword.length < 8) {
throw new Error('pathワードは8文字以ऊपरであるज़रूरीがあります');
}
const hashedPassword = await bcrypt.hash(newPassword, 12);
// トランザクションでpathワードupdateとtoken無効化
await prisma.$transaction([
prisma.user.update({
where: { id: resetRecord.userId },
data: { password: hashedPassword },
}),
prisma.passwordReset.update({
where: { id: resetRecord.id },
data: { used: true },
}),
]);
return { success: true };
}
}
リセットformのUI
// src/app/(auth)/reset-password/page.tsx
'use client';
import { useState } from 'react';
import { useSearchParams } from 'next/navigation';
export default function ResetPasswordPage() {
const searchParams = useSearchParams();
const token = searchParams.get('token');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [status, setStatus] = useState<'idle' | 'success' | 'error'>('idle');
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (password !== confirmPassword) {
setError('pathワードが一致しません');
return;
}
try {
const res = await fetch('/api/auth/reset-password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, password }),
});
if (!res.ok) throw new Error((await res.json()).error);
setStatus('success');
} catch (err: any) {
setError(err.message);
setStatus('error');
}
};
if (status === 'success') {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h2 className="text-2xl font-bold mb-4">pathワード updateしました</h2>
<a href="/login" className="text-blue-600 hover:underline">logインpageへ</a>
</div>
</div>
);
}
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<form onSubmit={handleSubmit} className="bg-white p-8 rounded-xl shadow-lg w-full max-w-md">
<h1 className="text-2xl font-bold mb-6">नयाpathワード</h1>
{error && <p className="text-red-500 text-sm mb-4">{error}</p>}
<div className="space-y-4">
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="नयाpathワード(8文字以ऊपर)"
className="w-full border rounded-lg px-4 py-3"
minLength={8}
required
/>
<input
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="pathワードのconfirm"
className="w-full border rounded-lg px-4 py-3"
required
/>
<button type="submit" className="w-full bg-blue-600 text-white py-3 rounded-lg font-medium">
pathワード update
</button>
</div>
</form>
</div>
);
}
securitychecklist
- tokenは暗号学的にsafeな乱数でgenerateする
- DBにはhash化したtokenを保存する
- tokenの有効期限を設ける(1時बीच程度)
- tokenは1回使用बादに無効化する
- userの存在有無を応答で漏らさない
関連記事
authentication全般の設計はauthenticationfeaturesのimplementation、二要素authenticationとの組み合わせは二要素authenticationのimplementationदेखें。
メール送信にはResend(resend.com)がシンプルでおすすめ है।
Related Posts
Claude Code से अपने Side Projects को Supercharge कैसे करें [Examples के साथ]
Claude Code से personal development projects को dramatically speed up करना सीखें। Real-world examples और idea से deployment तक practical workflow शामिल है।
Claude Code से Refactoring कैसे Automate करें
Claude Code से efficiently code refactoring automate करना सीखें। Real-world projects के लिए practical prompts और concrete refactoring patterns शामिल हैं।
Claude Code के साथ Complete CORS Configuration Guide
Claude Code का उपयोग करके complete CORS configuration guide सीखें। Practical tips और code examples शामिल हैं।