43 lines
1.2 KiB
TypeScript
43 lines
1.2 KiB
TypeScript
|
|
import { NextRequest, NextResponse } from 'next/server';
|
||
|
|
import { z } from 'zod';
|
||
|
|
|
||
|
|
import { errorResponse } from '@/lib/errors';
|
||
|
|
import { PORTAL_COOKIE } from '@/lib/portal/auth';
|
||
|
|
import { signIn } from '@/lib/services/portal-auth.service';
|
||
|
|
|
||
|
|
const bodySchema = z.object({
|
||
|
|
email: z.string().email(),
|
||
|
|
password: z.string().min(1),
|
||
|
|
});
|
||
|
|
|
||
|
|
const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24; // 24h, matches createPortalToken
|
||
|
|
|
||
|
|
export async function POST(req: NextRequest): Promise<NextResponse> {
|
||
|
|
let body: unknown;
|
||
|
|
try {
|
||
|
|
body = await req.json();
|
||
|
|
} catch {
|
||
|
|
return NextResponse.json({ error: 'Invalid request body' }, { status: 400 });
|
||
|
|
}
|
||
|
|
|
||
|
|
const parsed = bodySchema.safeParse(body);
|
||
|
|
if (!parsed.success) {
|
||
|
|
return NextResponse.json({ error: 'Invalid email or password' }, { status: 400 });
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const result = await signIn(parsed.data);
|
||
|
|
const res = NextResponse.json({ success: true });
|
||
|
|
res.cookies.set(PORTAL_COOKIE, result.token, {
|
||
|
|
httpOnly: true,
|
||
|
|
secure: process.env.NODE_ENV === 'production',
|
||
|
|
sameSite: 'lax',
|
||
|
|
path: '/',
|
||
|
|
maxAge: SESSION_MAX_AGE_SECONDS,
|
||
|
|
});
|
||
|
|
return res;
|
||
|
|
} catch (err) {
|
||
|
|
return errorResponse(err);
|
||
|
|
}
|
||
|
|
}
|