import { cookies } from 'next/headers'; import { NextRequest, NextResponse } from 'next/server'; // --------------------------------------------------------------------------- // POST /api/auth/login // --------------------------------------------------------------------------- // Special route handler for login. On success, sets the auth token in an // httpOnly cookie so it is never exposed to client-side JavaScript. // --------------------------------------------------------------------------- const API_BASE_URL = process.env.API_URL || process.env.NEXT_PUBLIC_API_URL || 'https://casera.treytartt.com/api'; const COOKIE_NAME = 'casera-token'; const COOKIE_MAX_AGE = 60 * 60 * 24 * 30; // 30 days export async function POST(request: NextRequest) { try { const body = await request.json(); const upstream = await fetch(`${API_BASE_URL}/auth/login/`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Timezone': request.headers.get('x-timezone') || Intl.DateTimeFormat().resolvedOptions().timeZone, }, cache: 'no-store', body: JSON.stringify(body), }); const data = await upstream.json().catch(() => null); if (!upstream.ok) { return NextResponse.json( data || { error: 'Login failed' }, { status: upstream.status }, ); } // Extract token from Go API response // The Go API returns { token: "...", user: { ... } } const token: string | undefined = data?.token; if (!token) { return NextResponse.json( { error: 'No token in response' }, { status: 500 }, ); } // Set httpOnly cookie const cookieStore = await cookies(); cookieStore.set(COOKIE_NAME, token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', path: '/', maxAge: COOKIE_MAX_AGE, }); // Return the full response (including user data) to the client, // but strip the raw token since it is now in the cookie. const { token: _stripped, ...safeData } = data; return NextResponse.json(safeData, { status: 200 }); } catch (error) { console.error('[auth/login] Error:', error); return NextResponse.json( { error: 'Internal server error' }, { status: 500 }, ); } }