/** * Custom Login Endpoint mit Audit-Logging * * POST /api/auth/login * * Dieser Endpoint wrappet den nativen Payload-Login und loggt fehlgeschlagene * Login-Versuche im Audit-Log. Erfolgreiche Logins werden durch den * afterLogin-Hook in der Users-Collection geloggt. * * Body: * - email: string (erforderlich) * - password: string (erforderlich) */ import { getPayload } from 'payload' import configPromise from '@payload-config' import { NextRequest, NextResponse } from 'next/server' import { logLoginFailed } from '@/lib/audit/audit-service' /** * Extrahiert Client-Informationen aus dem Request für Audit-Logging */ function getClientInfo(req: NextRequest): { ipAddress: string; userAgent: string } { const forwarded = req.headers.get('x-forwarded-for') const realIp = req.headers.get('x-real-ip') const ipAddress = (forwarded ? forwarded.split(',')[0]?.trim() : undefined) || realIp || 'unknown' const userAgent = req.headers.get('user-agent') || 'unknown' return { ipAddress, userAgent } } export async function POST(req: NextRequest): Promise { try { const payload = await getPayload({ config: configPromise }) const body = await req.json() const { email, password } = body // Validierung if (!email || !password) { return NextResponse.json( { error: 'E-Mail und Passwort sind erforderlich' }, { status: 400 }, ) } try { // Versuche Login über Payload const result = await payload.login({ collection: 'users', data: { email, password, }, }) // Erfolgreicher Login - afterLogin Hook hat bereits geloggt // Setze Cookie für die Session const response = NextResponse.json({ success: true, user: { id: result.user.id, email: result.user.email, }, message: 'Login erfolgreich', }) // Set the token cookie if (result.token) { response.cookies.set('payload-token', result.token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', path: '/', // Token expiration (default 2 hours) maxAge: result.exp ? result.exp - Math.floor(Date.now() / 1000) : 7200, }) } return response } catch (loginError) { // Login fehlgeschlagen - Audit-Log erstellen mit vollem Context const errorMessage = loginError instanceof Error ? loginError.message : 'Unbekannter Fehler' // Bestimme den Grund für das Fehlschlagen let reason = 'Unbekannter Fehler' if (errorMessage.includes('not found') || errorMessage.includes('incorrect')) { reason = 'Ungültige Anmeldedaten' } else if (errorMessage.includes('locked')) { reason = 'Konto gesperrt' } else if (errorMessage.includes('disabled')) { reason = 'Konto deaktiviert' } else if (errorMessage.includes('verify')) { reason = 'E-Mail nicht verifiziert' } else { reason = errorMessage } // Client-Info für Audit-Log const clientInfo = getClientInfo(req) // Audit-Log für fehlgeschlagenen Login (ohne PayloadRequest) await logLoginFailed(payload, email, reason) // Zusätzlich: Detailliertes Log mit IP/User-Agent direkt erstellen try { await (payload.create as Function)({ collection: 'audit-logs', data: { action: 'login_failed', severity: 'warning', entityType: 'users', userEmail: email, ipAddress: clientInfo.ipAddress, userAgent: clientInfo.userAgent, description: `Fehlgeschlagener Login-Versuch für ${email}: ${reason}`, metadata: { reason, source: '/api/auth/login' }, }, overrideAccess: true, }) } catch (auditError) { console.error('[Auth:Login] Failed to create detailed audit log:', auditError) } console.log( `[Audit:Auth] Login failed for ${email}: ${reason} (IP: ${clientInfo.ipAddress})`, ) return NextResponse.json( { success: false, error: 'Anmeldung fehlgeschlagen', // Keine detaillierten Infos aus Sicherheitsgründen }, { status: 401 }, ) } } catch (error) { console.error('[API:Auth] Login error:', error) return NextResponse.json( { error: 'Interner Serverfehler' }, { status: 500 }, ) } } /** * GET /api/auth/login * * Gibt API-Dokumentation zurück. */ export async function GET(): Promise { return NextResponse.json({ endpoint: '/api/auth/login', method: 'POST', description: 'Login endpoint with audit logging for failed attempts', body: { email: 'string (required)', password: 'string (required)', }, response: { success: { success: true, user: { id: 'number', email: 'string' }, message: 'string', }, error: { success: false, error: 'string', }, }, note: 'Successful logins are logged via afterLogin hook. Failed attempts are logged here.', }) }