// Zeigt, was Entra ID beim Anmelden tatsächlich mitgeschickt hat. // // Run with: node --env-file=.env.local supabase/entra-claims.ts // // Die Freischaltung über eine Entra-Gruppe hängt daran, wie der Anspruch im // Token heisst und wie er aussieht — das unterscheidet sich je nachdem, ob im // Mandanten „Sicherheitsgruppen" oder „der Anwendung zugewiesene Gruppen" // eingestellt ist. Diese Ausgabe ist die Grundlage für den Trigger; ohne sie // wäre er geraten. import { createClient } from "@supabase/supabase-js"; const SUPABASE_URL = process.env.NEXT_PUBLIC_SUPABASE_URL; const SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY; if (!SUPABASE_URL || !SERVICE_ROLE_KEY) { throw new Error("Missing NEXT_PUBLIC_SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY in the environment"); } const email = process.argv[2]; if (!email) { console.error("Aufruf: node --env-file=.env.local supabase/entra-claims.ts "); process.exit(1); } const supabase = createClient(SUPABASE_URL, SERVICE_ROLE_KEY, { auth: { autoRefreshToken: false, persistSession: false }, }); const { data, error } = await supabase.auth.admin.listUsers({ perPage: 1000 }); if (error) throw new Error(error.message); const matches = data.users.filter((u) => u.email?.toLowerCase() === email.toLowerCase()); if (matches.length === 0) { console.error(`Kein Konto zu ${email}. Vorhanden:`); for (const u of data.users) console.error(` ${u.email}`); process.exit(1); } // Mehrere Treffer sind der Normalfall in der Umstellungsphase: das alte Konto // mit Passwort und das neue über Entra sind für Supabase zwei Benutzer. for (const user of matches) { console.log(`\n── ${user.email} ──`); console.log(` id: ${user.id}`); console.log(` erstellt: ${user.created_at}`); console.log(` Anbieter: ${user.identities?.map((i) => i.provider).join(", ") || "keiner"}`); for (const identity of user.identities ?? []) { console.log(`\n identity_data (${identity.provider}) — von GoTrue aus der Antwort des Anbieters:`); console.log( Object.entries(identity.identity_data ?? {}) .map(([k, v]) => ` ${k}: ${JSON.stringify(v)}`) .join("\n") || " (leer)" ); } // Zum Vergleich, und als Warnung: hierher schreibt auch updateUser(), also // die angemeldete Person selbst. Als Grundlage für eine Freischaltung ist // das unbrauchbar. console.log("\n raw_user_meta_data — auch von der Person selbst beschreibbar, NICHT als Quelle verwenden:"); console.log( Object.entries(user.user_metadata ?? {}) .map(([k, v]) => ` ${k}: ${JSON.stringify(v)}`) .join("\n") || " (leer)" ); } const { data: profiles } = await supabase.from("profiles").select("id, email, role, is_active").eq("email", email); console.log(`\n── profiles zu ${email} ──`); for (const p of profiles ?? []) console.log(` ${p.id} role=${p.role} is_active=${p.is_active}`); if (!profiles?.length) console.log(" (keine Zeile — damit besteht kein Zugriff)");