import { createClient } from "https://esm.sh/@supabase/supabase-js@2.45.0"; /** * Verifies the caller is an authenticated admin. * Returns { ok: true } on success or { ok: false, response } with a * ready-to-return Response on failure. */ export async function requireAdmin( req: Request, corsHeaders: Record, ): Promise<{ ok: true; userId: string } | { ok: false; response: Response }> { const authHeader = req.headers.get("Authorization"); if (!authHeader?.startsWith("Bearer ")) { return { ok: false, response: new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" }, }), }; } const supabaseUrl = Deno.env.get("SUPABASE_URL"); const anonKey = Deno.env.get("SUPABASE_ANON_KEY"); const serviceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); if (!supabaseUrl || !anonKey || !serviceKey) { return { ok: false, response: new Response(JSON.stringify({ error: "Server misconfigured" }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" }, }), }; } const supabase = createClient(supabaseUrl, anonKey, { global: { headers: { Authorization: authHeader } }, }); const token = authHeader.replace("Bearer ", ""); const { data, error } = await supabase.auth.getClaims(token); if (error || !data?.claims?.sub) { return { ok: false, response: new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" }, }), }; } const userId = data.claims.sub as string; // Verify admin role via service-role client (bypasses RLS deterministically) const admin = createClient(supabaseUrl, serviceKey); const { data: role, error: roleErr } = await admin .from("user_roles") .select("role") .eq("user_id", userId) .eq("role", "admin") .maybeSingle(); if (roleErr || !role) { return { ok: false, response: new Response(JSON.stringify({ error: "Forbidden" }), { status: 403, headers: { ...corsHeaders, "Content-Type": "application/json" }, }), }; } return { ok: true, userId }; }