이번에 수파베이스의 소셜 로그인 기능을 적용하며 그동안 모호했던 Authentication(인증)과 Authorization(권한) 개념을 전통적인 방식과 비교해가며 정리해봤다.
사용자가 누군지 확인하는 절차
signInWithOAuth({ provider: 'google' }) 함수 호출인증된 사용자가 무엇을 할 수 있는지 결정하는 절차

[로그인 요청]
브라우저 → /login API → 서버 → DB → 결과 반환
[데이터 요청]
브라우저 → /posts API (토큰 포함)
→ 서버에서 인증된 유저인지 검증
→ 유저의 권한 확인 후 DB 쿼리
→ 응답 반환

[로그인 요청]
브라우저 → supabase.auth.signIn() 실행
→ Supabase Auth 서버가 OAuth 연동 및 토큰 발급
[데이터 요청]
브라우저 → supabase.from("posts").select("*")
→ Supabase가 토큰을 바탕으로 유저 식별
→ DB에서 권한 확인 후 데이터 응답
브라우저에서 supabase.from("...")으로 요청하면
create policy "사용자는 자신의 데이터만 조회 가능"
on todos for select
using (auth.uid() = user_id);
select * from todos
-- 이 쿼리에 다음이 자동으로 붙음
where auth.uid() = todos.user_id;
auth.uid()는 현재 로그인한 유저의 ID를 반환하며,
이 조건이 자동으로 모든 쿼리에 붙는다.
즉, 내가 select만 날려도 자동으로 내 데이터만 필터링된다.
다른 사람 데이터를 가져오려 해도 DB에서 거절당함.
| 항목 | 전통적인 방식 | Supabase 방식 |
|---|---|---|
| 인증 처리 | 서버가 Auth API 구현 | Supabase가 OAuth/Email로 인증 |
| 인증 정보 저장 | 서버 세션 or JWT | Supabase 쿠키 or JWT |
| DB 접근 | 서버만 가능 | 클라이언트가 직접 가능 |
| 권한 판단 위치 | 서버 코드 | DB(RLS) |
| 보안 제어 포인트 | 서버 로직 | DB 정책(RLS + Policy) |
브라우저에서 직접 DB 요청이라니 위험하지 않을까?라는 생각이 들 수 있다.
.select("*")만 써도, DB에서 내 데이터만 응답