46 lines
1.4 KiB
TypeScript
46 lines
1.4 KiB
TypeScript
// server/supabase/functions/_shared/auth.ts
|
|
// JWT 검증 + 인증된 유저 반환
|
|
|
|
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<string, string>): 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<User> {
|
|
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
|
|
}
|
|
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL') ?? ''
|
|
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
|
|
}
|