import { NextResponse } from "next/server"; import { aufruferAdresse, istHttps, oeffentlicheAdresse } from "@/lib/adressen"; import { logger } from "@/lib/logger"; import { SITZUNG_COOKIE, SITZUNG_LAUFZEIT_STUNDEN, sitzungErzeugen } from "@/lib/sitzung"; import { OIDC_COOKIE, oidcAbschliessen, oidcEinstellungen, OidcFehler, RUECKRUF_PFAD, } from "@/server/auth/oidc"; function cookieLesen(kopf: string | null, name: string): string | undefined { for (const teil of (kopf ?? "").split(";")) { const [schluessel, ...wert] = teil.trim().split("="); if (schluessel === name) return decodeURIComponent(wert.join("=")); } return undefined; } /** * Öffentlich: Rückkehr vom Identity Provider. Erfolg → Sitzungscookie und Weiterleitung zum Ziel; * Fehler → Anmeldeseite mit Code (`?sso=keine_gruppe` …), nie eine Fehlerseite mit Interna. */ export async function GET(anfrage: Request): Promise { const herkunft = new URL(anfrage.url).origin; const e = oidcEinstellungen(); const zurAnmeldung = (code: string) => NextResponse.redirect(oeffentlicheAdresse(`/anmelden?sso=${code}`, herkunft), 302); if (!e) return zurAnmeldung("aus"); // Die öffentliche Adresse: genau die, die als redirect_uri beim IdP registriert ist. const aktuell = oeffentlicheAdresse(RUECKRUF_PFAD + new URL(anfrage.url).search, herkunft); let antwort: NextResponse; try { const { benutzer, ziel } = await oidcAbschliessen( e, aktuell, cookieLesen(anfrage.headers.get("cookie"), OIDC_COOKIE), aufruferAdresse(anfrage.headers), ); antwort = NextResponse.redirect(oeffentlicheAdresse(ziel, herkunft), 302); antwort.cookies.set( SITZUNG_COOKIE, await sitzungErzeugen({ benutzerId: benutzer.id, herkunft: "oidc" }), { httpOnly: true, sameSite: "lax", secure: istHttps(anfrage.headers, anfrage.url), path: "/", maxAge: SITZUNG_LAUFZEIT_STUNDEN * 3600, }, ); } catch (fehler) { if (!(fehler instanceof OidcFehler)) logger.error({ err: fehler }, "OIDC-Rückruf fehlgeschlagen"); const code = fehler instanceof OidcFehler ? fehler.code : "idp"; // Beim Verknüpfen ist man schon angemeldet – die Meldung gehört dann in die Einstellungen. antwort = code === "schon_verknuepft" ? NextResponse.redirect(oeffentlicheAdresse(`/einstellungen?sso=${code}`, herkunft), 302) : zurAnmeldung(code); } antwort.cookies.set(OIDC_COOKIE, "", { path: "/api/v1/auth/oidc", maxAge: 0 }); return antwort; }