"use server"; import { AuthError } from "next-auth"; import { z } from "zod"; import { safeCallbackUrl } from "@/lib/safe-redirect"; import { signIn } from "@/auth"; // ===================================================================== // /login · Server Action // --------------------------------------------------------------------- // Wir kapseln `signIn("credentials", …)` damit: // • das Formular `useActionState` mit typisiertem Fehler-State nutzen kann // • der Redirect-Trigger (NEXT_REDIRECT) sauber durchgereicht wird // • generische Fehler ("Login fehlgeschlagen") weder Username-Existenz // noch Lockout-Status leaken (kein User-Enumeration). // ===================================================================== const loginSchema = z.object({ email: z.string().email("Bitte eine gültige E-Mail-Adresse angeben.").toLowerCase().trim(), password: z.string().min(1, "Passwort fehlt.").max(72), callbackUrl: z.string().optional(), }); export type LoginState = { errors?: { email?: string[]; password?: string[]; _form?: string[]; }; }; export async function loginAction( _prev: LoginState, formData: FormData, ): Promise { const parsed = loginSchema.safeParse(Object.fromEntries(formData)); if (!parsed.success) { return { errors: parsed.error.flatten().fieldErrors }; } const { email, password } = parsed.data; const redirectTo = safeCallbackUrl(parsed.data.callbackUrl); try { await signIn("credentials", { email, password, redirectTo, }); } catch (err) { // signIn wirft NEXT_REDIRECT bei Erfolg → das müssen wir bewusst // weiterwerfen, sonst wird der Redirect verschluckt. if (err instanceof AuthError) { return { errors: { _form: ["E-Mail oder Passwort ist nicht korrekt."] }, }; } throw err; } return {}; }