/* ===================================================================== lib/google-auth.js — Verifiziert ein Google-ID-Token ("Mit Google anmelden") serverseitig, für den öffentlichen Supporter-Login. WICHTIG — offener Punkt, siehe README.md "Supporter-Abo Setup": Braucht GOOGLE_CLIENT_ID (öffentlich, KEIN Geheimnis — steht bewusst als normale [vars]-Variable in wrangler.toml, nicht als Secret). Ohne gesetzten Wert bleibt "Mit Google anmelden" ausgeblendet (siehe supporter.js im Frontend) statt kaputt zu sein. Verifikation läuft über Googles offiziellen tokeninfo-Endpunkt (https://oauth2.googleapis.com/tokeninfo) — Google prüft dort Signatur, Ablaufzeit und Aussteller selbst und gibt die Nutzdaten zurück. Das spart eine eigene JWKS-/RS256-Prüfung im Worker, ist aber genauso sicher (offiziell von Google für Server-Side-Verifikation empfohlen). ===================================================================== */ export class GoogleAuthNotConfiguredError extends Error { constructor() { super("Google-Login ist noch nicht eingerichtet (GOOGLE_CLIENT_ID fehlt)."); this.name = "GoogleAuthNotConfiguredError"; this.code = "GOOGLE_AUTH_NOT_CONFIGURED"; } } /** * Prüft ein von Google Identity Services im Browser ausgestelltes ID-Token. * Gibt bei Erfolg die bestätigten Nutzerdaten zurück (E-Mail ist von Google * selbst bereits verifiziert — braucht deshalb KEINEN zusätzlichen * E-Mail-Bestätigungscode mehr, siehe routes/supporter.js). */ export async function verifyGoogleIdToken(env, credential) { if (!env.GOOGLE_CLIENT_ID) throw new GoogleAuthNotConfiguredError(); if (!credential) return { ok: false, reason: "Kein Token übergeben." }; const res = await fetch(`https://oauth2.googleapis.com/tokeninfo?id_token=${encodeURIComponent(credential)}`); if (!res.ok) return { ok: false, reason: "Google-Token konnte nicht geprüft werden." }; const data = await res.json(); if (data.aud !== env.GOOGLE_CLIENT_ID) return { ok: false, reason: "Token ist für eine andere App ausgestellt." }; if (!data.email || data.email_verified !== "true") return { ok: false, reason: "E-Mail-Adresse ist bei Google nicht bestätigt." }; return { ok: true, email: String(data.email).toLowerCase(), name: data.name || data.given_name || data.email.split("@")[0], }; }