test8 / src /app /api /auth /forgot-password /route.ts
simikkk's picture
Upload 93 files
eaab0a9 verified
Raw
History Blame Contribute Delete
2.78 kB
import { NextRequest, NextResponse } from 'next/server';
import { withDb } from '@/lib/api-handler';
import { db } from '@/lib/db';
import { z } from 'zod';
import { getClientIp } from '@/lib/validation';
import { rateLimit } from '@/lib/rate-limit';
const forgotPasswordSchema = z.object({
email: z.string().email('Please enter a valid email address'),
});
async function handler(request: NextRequest) {
try {
// ── Rate Limit: 3 per 15 minutes ─────────────────────────────────
const ip = getClientIp(request);
const { allowed, retryAfterMs } = await rateLimit(`forgot-pw:${ip}`, 3, 15 * 60_000);
if (!allowed) {
return NextResponse.json(
{ error: 'Too many reset attempts. Please try again later.' },
{
status: 429,
headers: { 'Retry-After': String(Math.ceil(retryAfterMs / 1000)) },
}
);
}
// ── Parse & Validate Body ─────────────────────────────────────────
const body = await request.json();
const parsed = forgotPasswordSchema.safeParse(body);
if (!parsed.success) {
return NextResponse.json(
{ error: parsed.error.issues[0].message },
{ status: 400 }
);
}
const { email } = parsed.data;
// ── Check if user exists ──────────────────────────────────────────
const user = await db.user.findUnique({ where: { email } });
if (user) {
// Generate a random 6-digit code
const code = String(Math.floor(100000 + Math.random() * 900000));
const expiresAt = new Date(Date.now() + 15 * 60 * 1000); // 15 minutes
// Invalidate any existing tokens for this email
await db.resetToken.updateMany({
where: { email, usedAt: null },
data: { usedAt: new Date() },
});
// Create new reset token
await db.resetToken.create({
data: {
email,
token: code,
expiresAt,
},
});
return NextResponse.json({
message: 'If an account exists with this email, a reset code has been generated.',
code, // Demo: return code so user can use it
});
}
// Return same message regardless to prevent email enumeration
return NextResponse.json({
message: 'If an account exists with this email, a reset code has been generated.',
});
} catch (error) {
console.error('[FORGOT_PASSWORD_ERROR]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
export const POST = withDb(handler);