Initial commit
This commit is contained in:
108
app/api/auth/login/route.ts
Normal file
108
app/api/auth/login/route.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { getPrisma } from "../../../../lib/db";
|
||||
import { verifyPassword } from "../../../../lib/auth/password";
|
||||
import { signSession } from "../../../../lib/auth/jwt";
|
||||
import { verifyCaptcha } from "../../../../lib/captcha";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
|
||||
const Body = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(1),
|
||||
captchaId: z.string().optional(),
|
||||
captchaCode: z.string().optional(),
|
||||
});
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const prisma = await getPrisma();
|
||||
const body = Body.safeParse(await req.json().catch(() => ({})));
|
||||
|
||||
if (!body.success) {
|
||||
return NextResponse.json({ ok: false, message: "Invalid input" }, { status: 400 });
|
||||
}
|
||||
if (!prisma) {
|
||||
return NextResponse.json({ ok: false, message: "Database not configured" }, { status: 503 });
|
||||
}
|
||||
|
||||
// Validate CAPTCHA if provided
|
||||
if (body.data.captchaId && body.data.captchaCode) {
|
||||
const captchaResult = verifyCaptcha(body.data.captchaId, body.data.captchaCode);
|
||||
if (!captchaResult.success) {
|
||||
return NextResponse.json({ ok: false, message: captchaResult.error || "CAPTCHA verification failed. Please try again." }, { status: 400 });
|
||||
}
|
||||
}
|
||||
|
||||
const email = body.data.email.toLowerCase();
|
||||
const password = body.data.password;
|
||||
|
||||
console.log("[LOGIN] Login attempt for:", email);
|
||||
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: { credential: true },
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
console.log("[LOGIN] User not found:", email);
|
||||
return NextResponse.json({ ok: false, message: "Invalid email or password" }, { status: 401 });
|
||||
}
|
||||
|
||||
if (!user.credential || !user.credential.password) {
|
||||
console.log("[LOGIN] No password credential for user:", email);
|
||||
return NextResponse.json({ ok: false, message: "Please use Google sign-in for this account" }, { status: 401 });
|
||||
}
|
||||
|
||||
const valid = await verifyPassword(password, user.credential.password);
|
||||
|
||||
if (!valid) {
|
||||
console.log("[LOGIN] Invalid password for:", email);
|
||||
return NextResponse.json({ ok: false, message: "Invalid email or password" }, { status: 401 });
|
||||
}
|
||||
|
||||
if (!user.isActive) {
|
||||
console.log("[LOGIN] Inactive account:", email);
|
||||
return NextResponse.json({ ok: false, message: "Account is inactive. Please contact support." }, { status: 403 });
|
||||
}
|
||||
|
||||
// Create session token
|
||||
const token = await signSession({
|
||||
sub: user.id,
|
||||
role: user.role as "ADMIN" | "USER",
|
||||
email: user.email,
|
||||
forcePasswordReset: user.forcePasswordReset || false,
|
||||
});
|
||||
|
||||
console.log("[LOGIN] Session created for:", email, "with role:", user.role);
|
||||
|
||||
// Set cookie
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set("ep_session", token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "lax",
|
||||
maxAge: 7 * 24 * 60 * 60, // 7 days
|
||||
path: "/",
|
||||
});
|
||||
|
||||
console.log("[LOGIN] Login successful for:", email);
|
||||
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
emailVerified: user.emailVerified,
|
||||
forcePasswordReset: user.forcePasswordReset,
|
||||
},
|
||||
});
|
||||
} catch (e: any) {
|
||||
console.error("[LOGIN] Error:", e);
|
||||
return NextResponse.json({ ok: false, message: "Server error: Unable to process request" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user