상황 - 오류 없는 빈 값 조회

현재 개인 사이드 프로젝트에서 Supabse를 사용해서 백엔드를 구성하고 있다. 사용자 프로필 정보를 담는 profiles 테이블을 만들었다. 이 propfiles 테이블의 데이터를 조회할 때, 본인꺼만 조회할 수 있도록 RLS 정책을 지정해 놓았다. 개발 중 웹훅 수신 로직에서 사용자 이메일 값을 기반으로 profile에서 사용자 id를 파싱 해야하는 상황이 생겼다. 이때 profiles에 접근해서 응답을 보니 항상 빈 배열 값이 나오는 문제가 생겼다.

원인 분석

  • Supabse의 profiles 테이블에 RLS(행 수준 보안)가 적용되어 있다.
  • RLS 정책이 "본인(로그인된 유저)만 자신의 profile을 select 할 수 있다."로 되어 있으면, 서버에서 웹훅(즉, 외부 시스템)이 호출할 때는 인증된 유저가 없으므로, 어떤 profile도 조회할 수 없다.

해결 방법

1. Service Role Key 사용

  • Supabse의 Service Role Key(서버 전용 시크릿 키)를 사용하면, RLS를 무시하고 모든 데이터에 접근이 가능했다.
  • 현재는 Service Role Key를 사용하지 않는 supabse 객체를 클라이언트, 서버단 2개로 나누어서 사용 중이다.
  • 이 방식은 서버에서만 사용해야 하며, 클라이언트에서는 절대 노출하면 안 된다.
import { supabaseAdmin } from '@/lib/supabase-server'; // Service Role Key 사용

const { data: userProfile } = await supabaseAdmin
  .from('profiles')
  .select('id')
  .eq('email', attr.user_email)
  .single();

2. 웹훅 전용 RLS 정책 추가

  • 만약 Service Role Key를 사용하지 않고, 일반 API Key로만 접근해야 한다면,
  • 웹훅에서 오는 요청의 IP나 특정 헤더, 혹은 별도의 인증 토큰을 기반으로 RLS 정책을 완화할 수 있다.
  • 하지만, Service Role Key를 사용하는 것이 더 쉽고 안전하다.

결론

  • 웹훅 등 서버에서 RLS를 우회해야 할 때는 Service Role Key를 사용하는 supabase client로 쿼리하기(쉽게 말해, 관리자용 supabse client)
  • 모든 곳에서 Service Role Key를 사용하는 supabase client로 하지말고, 필요한 부분에서만 사용하기

적용 예시

import { supabaseAdmin } from '@/lib/supabase-server'; // Service Role Key 사용

let userId = '';
if (attr.user_email) {
  const { data: userProfile } = await supabaseAdmin
    .from('profiles')
    .select('id')
    .eq('email', attr.user_email)
    .single();
  userId = userProfile?.id ?? '';
}
반응형

+ Recent posts