82 lines
2.1 KiB
TypeScript

/**
* 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<AuthResult> {
// 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<string, string>
) {
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;
}