// server/supabase/functions/_shared/auth.ts // JWT 검증 + 인증된 유저 반환 // @ts-expect-error — Deno 런타임 import (타입 보강은 deno.json 또는 skipLibCheck) import { createClient, type User } from 'https://esm.sh/@supabase/supabase-js@2.39.7' export interface AuthError { status: number message: string } export function authErrorResponse(error: AuthError, corsHeaders: Record): Response { return new Response(JSON.stringify({ error: error.message }), { status: error.status, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }) } /** * Authorization 헤더에서 JWT를 추출하여 유저를 검증한다. * 실패 시 예외 대신 AuthError 객체를 throw. */ export async function requireUser(req: Request): Promise { const authHeader = req.headers.get('Authorization') if (!authHeader) { // eslint-disable-next-line @typescript-eslint/no-throw-literal throw { status: 401, message: 'Missing Authorization header' } as AuthError } // @ts-expect-error — Deno.env는 Deno 런타임 전역 const supabaseUrl = Deno.env.get('SUPABASE_URL') ?? '' // @ts-expect-error — Deno.env는 Deno 런타임 전역 const supabaseAnonKey = Deno.env.get('SUPABASE_ANON_KEY') ?? '' const supabase = createClient(supabaseUrl, supabaseAnonKey, { global: { headers: { Authorization: authHeader } } }) const { data: { user }, error } = await supabase.auth.getUser() if (error || !user) { // eslint-disable-next-line @typescript-eslint/no-throw-literal throw { status: 401, message: error?.message ?? 'Invalid auth token' } as AuthError } return user }