/** * Helper centralizado para autenticação híbrida * * ARQUITETURA: * - Autenticação = External Supabase (source of truth) * - Own Supabase = apenas dados complementares (sem validar JWT) * * COMO USAR: * 1. Passar service_role_key no header "Authorization" * 2. Passar external JWT no header "x-external-jwt" * 3. A function valida o JWT no External Supabase */ import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; export interface AuthResult { user: any; externalSupabase: any; ownSupabase: any; } export async function validateExternalAuth(req: Request): Promise { // 1. Pegar JWT do External Supabase const externalJwt = req.headers.get("x-external-jwt"); if (!externalJwt) { throw new Error("Missing x-external-jwt header"); } // 2. Validar JWT no External Supabase (source of truth) const externalSupabase = createClient( Deno.env.get("EXTERNAL_SUPABASE_URL")!, Deno.env.get("EXTERNAL_SUPABASE_ANON_KEY") || Deno.env.get("EXTERNAL_SUPABASE_KEY")!, { global: { headers: { Authorization: `Bearer ${externalJwt}` } } } ); const { data: { user }, error: authError, } = await externalSupabase.auth.getUser(); if (authError || !user) { throw new Error( `Invalid external JWT: ${authError?.message || "User not found"}` ); } // 3. Cliente para NOSSO Supabase (service_role = acesso total) const ownSupabase = createClient( Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")! ); return { user, externalSupabase, ownSupabase, }; } export function createAuthErrorResponse( error: Error, corsHeaders: Record ) { return new Response( JSON.stringify({ success: false, error: error.message, }), { status: 401, headers: { ...corsHeaders, "Content-Type": "application/json" }, } ); } export function getExternalJwt(req: Request): string { const jwt = req.headers.get("x-external-jwt"); if (!jwt) throw new Error("Missing x-external-jwt header"); return jwt; }