Supabase Authentication 시스템

Supabase Authentication 시스템

1. Supabase 인증 시스템의 철학과 아키텍처

Supabase 인증 시스템은 단순한 사용자 로그인 기능을 넘어, 데이터베이스와 깊이 통합된 독창적인 아키텍처를 기반으로 설계되었다. 이는 인증(Authentication)을 데이터 접근 제어의 일부로 간주하는 철학적 전환을 의미하며, 개발자가 보다 일관되고 안전한 방식으로 인가(Authorization)를 구현하도록 유도한다.

1.1 Postgres-네이티브 접근 방식: 인증과 데이터의 통합

Supabase Auth의 가장 근본적인 특징은 사용자를 별도의 서비스가 아닌, 프로젝트의 PostgreSQL 데이터베이스 내 auth.users 테이블에 직접 저장한다는 점이다.1 이 Postgres-네이티브 접근 방식은 인증 시스템과 애플리케이션 데이터베이스 간의 경계를 허물어, 두 시스템을 하나의 유기적인 전체로 통합한다.

이러한 설계는 개발자가 표준 SQL을 사용하여 인증 데이터와 애플리케이션 데이터를 직접 연결할 수 있게 해준다. 예를 들어, profiles 테이블을 생성하고 auth.users 테이블의 id를 외래 키(foreign key)로 참조하여 사용자 프로필 정보를 확장하는 작업이 매우 직관적으로 이루어진다.3 이는 인증과 데이터베이스가 분리된 다른 솔루션과 비교했을 때 Supabase가 갖는 핵심적인 차별점이다.1

이러한 아키텍처는 인증이라는 개념을 재정의하는 결과를 낳는다. Supabase는 인증을 단순히 ‘누구인지 확인하는’ 절차로 보지 않고, ’어떤 데이터에 접근할 수 있는지’를 결정하는 데이터 문제로 접근한다. 사용자를 데이터베이스의 한 행(row)으로 취급함으로써, 인증된 사용자의 신원은 데이터베이스 쿼리의 자연스러운 필터링 조건이 된다. 이 설계는 필연적으로 PostgreSQL의 강력한 기능인 행 수준 보안(Row Level Security, RLS)을 인증 시스템의 핵심 인가 모델로 채택하는 논리적 귀결로 이어진다.1 즉, 아키텍처의 선택이 인가 모델을 결정한 것이다. 결과적으로 개발자는 애플리케이션 코드에 복잡한 권한 확인 로직을 분산시키는 대신, 데이터베이스 스키마와 정책(Policy) 설계에 집중하게 된다. 이는 백엔드 로직을 단순화하는 동시에, 데이터베이스 설의 중요성을 극적으로 높이는 구조적 특징을 가진다.6

1.2 GoTrue: 오픈소스 인증 서버의 역할

Supabase 인증 시스템의 핵심 엔진은 Go 언어로 작성된 오픈소스 API 서버인 ’GoTrue’이다.2 GoTrue는 본래 Netlify에서 개발되었으나, Supabase가 이를 포크(fork)하여 독자적으로 기능을 대폭 확장했다.8 Supabase 프로젝트가 배포될 때, 각 프로젝트마다 독립적인 GoTrue 인스턴스가 함께 배포된다.2

GoTrue 서버는 다음과 같은 핵심 역할을 수행한다.

  • JWT(JSON Web Token)의 발급, 검증, 갱신 2
  • Google, GitHub 등 외부 OAuth 제공자와의 통신 중재 2
  • 사용자 가입, 로그인, 비밀번호 재설정 등 사용자 관리 API 엔드포인트 제공 8

GoTrue가 오픈소스라는 점은 개발자에게 높은 유연성과 통제권을 부여한다. 이는 특정 벤더에 대한 종속성(vendor lock-in)을 줄여주며, 필요시 전체 인증 시스템을 자체적으로 호스팅(self-hosting)할 수 있는 가능성을 열어준다.1 개발자는

GOTRUE_ 접두사가 붙은 환경 변수를 통해 JWT 만료 시간, 리디렉션 URL 허용 목록, 외부 제공자 설정 등 시스템의 세부 동작을 정밀하게 제어할 수 있다.8

그러나 이러한 유연성은 복잡성이라는 양면성을 가진다. GoTrue는 CLI와 환경 변수 기반의 설정을 중심으로 하는 개발자 친화적 도구로 설계되었다.10 이로 인해 SAML 프로토콜이나 IDP(Identity Provider) 설정에 익숙한 기술팀에게는 강력한 도구가 되지만, 비기술적인 IT 관리자가 사용자, 역할, 권한을 직관적으로 관리하기 위한 포괄적인 그래픽 사용자 인터페이스(GUI)는 상대적으로 부족하다는 평가를 받는다.10 이는 Supabase Auth가 ‘개발자 우선’ 철학을 기반으로 하고 있음을 명확히 보여주는 지점이다.

1.3 4계층 아키텍처 심층 분석

Supabase Auth는 명확하게 역할이 분리된 4개의 논리적 계층으로 구성되어 시스템의 안정성과 확장성을 보장한다.2

  1. 클라이언트 계층 (Client Layer): 최종 사용자 애플리케이션(웹 브라우저, 모바일 앱 등)에서 실행되는 계층이다. Supabase는 JavaScript(@supabase/supabase-js), Flutter, Swift 등 다양한 언어를 위한 공식 클라이언트 SDK를 제공한다.2 이 SDK들은 GoTrue 서버와의 HTTP 통신, 로컬 스토리지 또는 쿠키를 이용한 토큰 저장 및 자동 갱신, 다른 Supabase 제품(Database, Storage 등)과의 원활한 통합 등 복잡한 작업을 추상화하여 개발자가 인증 로직 구현에만 집중할 수 있도록 돕는다.2
  2. API 게이트웨이 (Kong API Gateway): 모든 Supabase 제품군으로 향하는 요청의 단일 진입점 역할을 한다. Kong은 요청 라우팅, API 키 기반의 초기 인증, 부하 분산 등의 역할을 수행하며 전체 시스템의 안정성을 높인다.2
  3. 인증 서비스 (Auth Service - GoTrue): 인증 로직의 핵심을 담당하는 계층이다. 클라이언트로부터 요청을 받아 JWT를 발급하고, 외부 OAuth 제공자와 통신하며, 데이터베이스의 auth 스키마와 상호작용하여 사용자 정보를 관리한다.2
  4. 데이터베이스 (Postgres): 모든 인증 정보의 최종 저장소다. 사용자 정보는 auth.users 테이블에, 세션 정보는 auth.refresh_tokens 테이블에 저장되는 등, 관련 데이터는 auth 스키마 내에 체계적으로 관리된다. 보안을 위해 이 auth 스키마는 자동 생성된 REST API를 통해 직접 노출되지 않는다.2

2. 인증(Authentication): 사용자 신원 확인 메커니즘 분석

Supabase는 현대적인 애플리케이션이 요구하는 거의 모든 인증 시나리오를 지원하기 위해 다채로운 인증 방법을 제공한다. 각 방법은 고유한 작동 원리와 보안적 특성을 가지며, 개발자는 이를 조합하여 최적의 사용자 경험을 설계할 수 있다.

2.1 비밀번호 기반 인증

가장 전통적인 방식인 이메일 또는 전화번호와 비밀번호 조합을 통한 인증이다. Supabase 클라이언트 라이브러리의 signUp()signInWithPassword() (과거 signIn()) 함수를 통해 간단하게 구현할 수 있다.3

구현 흐름은 다음과 같다. 사용자가 signUp()을 호출하면, GoTrue 서버는 입력된 비밀번호를 강력한 해시 함수인 bcrypt를 사용하여 해싱한 후, 그 결과를 auth.users 테이블의 encrypted_password 컬럼에 저장한다.1 이 과정에서 무작위로 생성된 솔트(salt)가 각 해시에 추가되어 보안성을 더욱 강화한다.16 이메일 확인(Email Confirmation) 기능이 활성화된 경우, 사용자에게 확인 토큰이 포함된 이메일이 발송되며, 사용자가 이 링크를 클릭해야 계정이 최종적으로 활성화된다. 로그인 시에는 signInWithPassword() 함수가 호출되고, GoTrue는 제출된 비밀번호를 동일한 방식으로 해싱하여 데이터베이스에 저장된 해시 값과 비교한다. 일치할 경우, 새로운 JWT(액세스 토큰 및 리프레시 토큰)를 발급하여 클라이언트에 반환한다.

Supabase는 비밀번호 보안을 강화하기 위한 여러 설정 옵션을 제공한다. 관리자는 대시보드에서 최소 비밀번호 길이, 필수 문자 조합(대/소문자, 숫자, 특수 기호)을 강제할 수 있으며, 특히 주목할 만한 기능은 유출된 비밀번호 사용을 방지하는 옵션이다. 이 기능은 사용자가 입력한 비밀번호를 HaveIBeenPwned.org의 Pwned Passwords API와 대조하여 이미 유출된 적이 있는 안전하지 않은 비밀번호의 사용을 원천적으로 차단한다.16

2.2 소셜 로그인 (OAuth 2.0)

Google, GitHub, Facebook, Apple 등 널리 사용되는 외부 OAuth 2.0 제공자를 통한 로그인을 지원한다.3 이는 사용자가 새로운 계정을 만들고 비밀번호를 기억해야 하는 부담을 줄여주어 가입 전환율을 높이고 사용자 경험을 크게 개선하는 효과적인 방법이다.17

구현 흐름은 표준 OAuth 2.0 절차를 따르며, 보안이 강화된 PKCE(Proof Key for Code Exchange) 흐름을 기반으로 한다.

  1. 제공자 설정: 개발자는 먼저 Google Cloud Console이나 GitHub Developer Settings와 같은 각 OAuth 제공자의 개발자 포털에서 OAuth 애플리케이션을 생성해야 한다. 이 과정에서 Client ID와 Client Secret을 발급받고, Supabase 대시보드의 ‘Authentication > Providers’ 섹션에서 제공하는 고유한 콜백 URL(예: https://<project-ref>.supabase.co/auth/v1/callback)을 제공자 설정에 ’승인된 리디렉션 URI’로 등록해야 한다.18
  2. Supabase 설정: 발급받은 Client ID와 Secret을 Supabase 대시보드의 해당 제공자 설정란에 입력하고 활성화한다.18
  3. 로그인 요청: 클라이언트 애플리케이션에서 supabase.auth.signInWithOAuth({ provider: 'google' })와 같은 함수를 호출한다.18 서버 사이드 렌더링(SSR) 환경에서는 PKCE 흐름을 올바르게 처리하기 위해 redirectTo 옵션을 사용하여 인증 후 돌아올 애플리케이션 내의 특정 콜백 경로를 명시해야 한다.18
  4. 인증 및 토큰 교환: 사용자는 해당 제공자의 로그인 페이지로 리디렉션되어 인증을 수행한다. 인증이 성공하면, 제공자는 authorization code와 함께 Supabase의 콜백 URL로 사용자를 리디렉션한다. Supabase의 GoTrue 서버는 이 code를 받아 자신의 Client Secret과 함께 제공자의 토큰 엔드포인트로 전송하여 액세스 토큰과 교환한다.
  5. 사용자 처리 및 세션 발급: GoTrue는 제공자로부터 받은 액세스 토큰을 사용하여 사용자 프로필 정보(특히 이메일 주소)를 조회한다. 이 이메일 주소를 기준으로 auth.users 테이블을 확인하여, 기존 사용자가 있으면 새로운 OAuth ID를 해당 사용자에게 연결(Identity Linking)하고, 신규 사용자인 경우 새로운 사용자 레코드를 생성한다.21 마지막으로, Supabase 애플리케이션을 위한 JWT 세션을 생성하여 redirectTo에 명시된 URL로 사용자를 리디렉션한다.

중요한 점은, Supabase는 보안상의 이유로 외부 제공자(예: Google)의 액세스 토큰이나 리프레시 토큰을 데이터베이스에 저장하지 않는다는 것이다. 만약 개발자가 사용자를 대신하여 Google Calendar API를 호출하는 등 추가적인 작업이 필요하다면, 로그인 성공 시 반환되는 provider_tokenprovider_refresh_token을 직접 안전한 서버 환경에 저장하고 관리해야 할 책임이 있다.17

2.3 비밀번호 없는 인증: 매직 링크 및 OTP

매직 링크와 OTP(One-Time Password)는 사용자가 비밀번호를 생성하거나 기억할 필요 없이 이메일 또는 SMS를 통해 인증을 완료하는 방식이다.22

매직 링크의 작동 원리는 다음과 같다.

  1. 클라이언트에서 supabase.auth.signInWithOtp({ email: '...' }) 함수를 호출한다. 이 함수는 이름과 달리 기본적으로 매직 링크를 전송하는 역할을 한다.22
  2. GoTrue 서버는 해당 이메일 주소로 고유하고 암호화된 토큰이 포함된 일회용 URL(매직 링크)을 보낸다. 이 링크는 기본적으로 24시간 동안 유효하며 한 번만 사용할 수 있다.25
  3. 사용자가 이메일에서 해당 링크를 클릭하면, 브라우저는 Supabase의 인증 엔드포인트로 이동한다. GoTrue 서버는 토큰의 유효성을 검증하고, 성공 시 새로운 JWT 세션을 발급한 후, 미리 설정된 redirectTo URL로 사용자를 리디렉션하여 로그인 절차를 완료한다.

이메일 OTP를 사용하려면 이메일 템플릿을 수정해야 한다. Supabase 대시보드에서 매직 링크 이메일 템플릿의 내용을 {{.ConfirmationURL }} 변수 대신 6자리 코드인 {{.Token }} 변수를 포함하도록 변경하면, signInWithOtp 함수가 매직 링크 대신 OTP 코드를 발송한다.22 사용자가 이메일로 받은 OTP를 입력하면, 클라이언트는 supabase.auth.verifyOtp() 함수를 호출하여 토큰을 검증하고 세션을 발급받는다.22

매직 링크는 편리하지만, 사용자의 이메일 계정이 탈취될 경우 애플리케이션 계정의 보안이 그대로 위협받는다는 내재적 위험을 가진다. Supabase는 이 위험을 완화하기 위해 여러 계층의 보안 장치를 마련했다. 첫째, 링크 자체를 일회용으로 만들고 만료 시간을 설정하여 재사용 및 시간 경과에 따른 위험을 줄인다.25 둘째, 서버 사이드 인증 환경에서는 PKCE 흐름을 적용하여, 링크가 중간에 탈취되더라도 최초 요청을 보낸 브라우저 세션이 아니면 인증을 완료할 수 없도록 막는다. 이는 보안성을 크게 향상시키지만, 데스크톱에서 받은 링크를 모바일에서 여는 등의 사용 편의성을 일부 제한한다.25 셋째, 인증 성공 후 리디렉션될 수 있는 URL을 허용 목록(allow list) 기반으로 엄격하게 관리하여, 악의적인 사이트로 사용자를 유도하는 피싱 공격을 방지한다.28 이는 Supabase가 각 인증 방식의 내재적 취약점을 이해하고 이를 완화하기 위한 다층적 보안 메커니즘을 아키텍처 수준에서 고려하고 있음을 보여준다.

2.4 기타 인증 방식

  • 전화번호 인증: Twilio, MessageBird와 같은 외부 SMS 게이트웨이 서비스와 연동하여 전화번호 기반의 OTP 로그인 및 가입 기능을 구현할 수 있다.1
  • 엔터프라이즈 SSO (Single Sign-On): SAML 2.0 및 Azure Active Directory를 지원하여, 기업 환경에서 기존의 ID 시스템을 통해 Supabase 애플리케이션에 로그인할 수 있도록 한다.3
  • 익명 로그인: supabase.auth.signInAnonymously() 함수를 통해 임시 익명 사용자를 생성할 수 있다. 이 익명 사용자는 앱의 기능을 사용하다가 나중에 이메일, 비밀번호 또는 소셜 계정을 연결(linkIdentity 함수 사용)하여 영구적인 사용자로 전환될 수 있다.4
인증 방식핵심 API주요 특징 및 보안 고려사항관련 Snippet
이메일/비밀번호signUp, signInWithPasswordbcrypt 해싱, 비밀번호 정책 강화, 유출된 비밀번호 확인 기능 제공.1
소셜 로그인(OAuth)signInWithOAuthGoogle, GitHub 등 다수 제공자 지원. PKCE 흐름 지원. 제공자 토큰은 DB에 미저장.3
매직 링크signInWithOtp비밀번호 불필요. 이메일 계정 보안에 의존. 일회용, 만료 시간 존재.22
전화번호 OTPsignInWithOtp, verifyOtp외부 SMS 제공자(예: Twilio) 필요. 모바일 중심 앱에 유용.1
익명 로그인signInAnonymously임시 사용자 생성. 추후 영구 계정으로 전환 가능 (linkIdentity).4

3. 인가(Authorization): PostgreSQL 행 수준 보안(RLS)의 심층 통합

Supabase Auth의 가장 독창적이고 강력한 기능은 인가(Authorization)를 처리하는 방식에 있다. Supabase는 PostgreSQL의 내장 기능인 행 수준 보안(Row Level Security, RLS)을 인증 시스템과 완벽하게 통합하여, 데이터베이스 계층에서 직접적이고 세밀한 접근 제어를 구현한다.

3.1 RLS의 개념과 데이터베이스 중심 인가 모델

RLS는 특정 사용자가 테이블의 어떤 행(row)에 대해 특정 작업(SELECT, INSERT, UPDATE, DELETE)을 수행할 수 있는지를 제어하는 규칙, 즉 정책(Policy)을 정의하는 PostgreSQL의 기능이다.5 Supabase는 이 기능을 활용하여 애플리케이션 미들웨어나 백엔드 코드에 흩어져 있던 인가 로직을 데이터베이스로 중앙화한다.3

RLS를 특정 테이블에 활성화(ENABLE ROW LEVEL SECURITY)하면, 기본적으로 해당 테이블에 대한 모든 접근이 차단되는 ‘기본 거부(default-deny)’ 원칙이 적용된다.6 이후, 명시적으로 정의된 정책을 통해서만 데이터 접근이 허용된다. 이 방식의 가장 큰 장점은 보안 규칙이 데이터와 함께 존재한다는 점이다. 따라서 자동 생성된 REST API, 직접적인 데이터베이스 연결, 서버리스 함수 등 어떤 경로로 데이터에 접근하더라도 동일한 보안 정책이 일관되게 강제된다.6 이는 애플리케이션 코드의 논리적 오류나 버그로 인해 발생할 수 있는 데이터 유출 위험을 원천적으로 감소시키는 강력한 ‘심층 방어(defense in depth)’ 전략을 제공한다.6

3.2 RLS 정책(Policy) 작성 및 활용

RLS 정책은 표준 SQL을 사용하여 정의되므로, 데이터베이스 관리자와 개발자가 쉽게 이해하고 작성할 수 있다.6 정책의 기본 구조는 다음과 같다.

CREATE POLICY "policy_name"
ON table_name
FOR <command>
TO <role>
USING (boolean_expression)
WITH CHECK (boolean_expression);

정책의 핵심은 USING 절과 WITH CHECK 절에 정의되는 불리언 표현식(boolean expression)이다.

  • USING (expression): 이 절은 기존에 존재하는 행에 대한 접근(SELECT, UPDATE, DELETE)을 시도할 때 평가된다. expressiontrue를 반환하는 행만이 사용자에게 보이거나 조작이 허용된다.32

  • WITH CHECK (expression): 이 절은 새로운 행을 추가(INSERT)하거나 기존 행을 수정(UPDATE)할 때 평가된다. expressiontrue를 반환해야만 해당 쓰기 작업이 허용된다. 이는 데이터 무결성을 강제하는 데 사용된다.32

UPDATE 정책은 USINGWITH CHECK를 모두 가질 수 있는데, USING은 수정할 행을 선택하는 조건을, WITH CHECK는 수정된 결과 행이 만족해야 할 조건을 검사한다.

Supabase는 RLS 정책 작성을 더욱 편리하게 만들기 위해 인증 컨텍스트에 접근할 수 있는 몇 가지 내장 헬퍼 함수를 제공한다.

  • auth.uid(): 현재 API 요청을 보낸 인증된 사용자의 고유 ID(UUID)를 반환한다. “사용자는 자신의 데이터만 접근할 수 있다“와 같은 가장 일반적인 정책을 작성하는 데 사용된다.3
  • auth.jwt(): 현재 사용자의 전체 JWT 페이로드를 JSONB 객체로 반환한다. 이를 통해 이메일, 역할(role), app_metadata에 저장된 커스텀 클레임 등 더 복잡하고 풍부한 정보를 기반으로 정책을 작성할 수 있다.5

3.3 RLS 정책 구현 시나리오

RLS를 활용한 구체적인 인가 시나리오는 다음과 같다.

3.3.1 시나리오 1: 사용자는 자신의 프로필만 수정할 수 있다.

-- profiles 테이블에 RLS 활성화
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

-- 본인 프로필만 보고 수정할 수 있는 정책 생성
CREATE POLICY "Users can view and update their own profile"
ON profiles FOR ALL
USING ( auth.uid() = id )
WITH CHECK ( auth.uid() = id );

이 정책에서 USING 절은 SELECT 시 현재 로그인한 사용자의 ID(auth.uid())가 프로필 행의 id와 일치하는 경우에만 해당 행을 반환하도록 제한한다. WITH CHECK 절은 INSERTUPDATE 시 새로운 데이터의 id 값이 반드시 현재 사용자의 ID와 일치하도록 강제하여, 다른 사용자의 프로필을 생성하거나 수정하는 행위를 방지한다.3

3.3.2 시나리오 2: 팀 멤버는 소속된 팀의 정보만 볼 수 있다.

teams 테이블과 사용자와 팀을 연결하는 members 테이블이 있다고 가정할 때, 다음과 같은 정책을 수립할 수 있다.

-- 팀 멤버만 해당 팀 정보를 볼 수 있는 정책
CREATE POLICY "Team members can view their team details"
ON teams FOR SELECT
USING (
id IN (
SELECT team_id FROM members WHERE user_id = auth.uid()
)
);

이 정책의 USING 절은 서브쿼리를 사용하여 members 테이블에서 현재 사용자가 속한 모든 team_id를 조회하고, teams 테이블에서 해당 id를 가진 행들만 SELECT 할 수 있도록 허용한다. 이는 다중 테넌시(multi-tenancy) 애플리케이션에서 각 테넌트의 데이터를 안전하게 격리하는 핵심적인 패턴이다.3

RLS는 매우 강력하지만, 성능과 복잡성 간의 트레이드오프를 내포한다. RLS 정책 내부에 복잡한 서브쿼리나 여러 테이블을 조인하는 로직을 포함하면, 해당 테이블에 대한 모든 CRUD 작업마다 이 정책 쿼리가 추가로 실행된다. 만약 정책 쿼리가 비효율적이거나 관련 컬럼에 인덱스가 제대로 설정되지 않았다면, 이는 데이터베이스 성능에 심각한 병목 현상을 유발할 수 있다.5 따라서 RLS를 효과적으로 사용하기 위해서는 단순히 SQL 정책을 작성하는 능력을 넘어, PostgreSQL의 쿼리 최적화와 실행 계획(Execution Plan) 분석에 대한 깊은 이해가 필수적이다. 개발자는 보안 정책이 성능 저하의 원인이 되지 않도록 데이터베이스 스키마와 인덱스를 신중하게 설계해야 한다.6

4. JWT(JSON Web Token) 관리 및 세션 생명주기

Supabase는 토큰 기반 인증의 표준인 JWT를 사용하여 세션을 관리한다. 특히 상태 비저장(stateless)과 상태 저장(stateful) 방식의 장점을 결합한 하이브리드 아키텍처를 채택하여 보안과 성능의 균형을 맞추었다.

4.1 하이브리드 토큰 아키텍처

Supabase Auth는 두 가지 종류의 토큰을 사용하여 세션을 관리하는 하이브리드 모델을 사용한다.1

  • 액세스 토큰 (Access Token): 상대적으로 짧은 만료 시간(기본 1시간, 설정 가능)을 가진 표준 JWT다.13 이 토큰의 페이로드에는 사용자의 신원(sub 클레임)과 권한 정보가 포함되어 있다. 클라이언트는 모든 API 요청의 Authorization: Bearer <token> 헤더에 이 토큰을 담아 보낸다. 서버(PostgREST)는 데이터베이스를 조회할 필요 없이 토큰의 서명만 검증하면 되므로, 요청 처리가 빠르고 확장성이 뛰어나다.34
  • 리프레시 토큰 (Refresh Token): 긴 유효 기간을 가지며(기본적으로 만료되지 않음), 한 번만 사용할 수 있다.13 이 토큰은 클라이언트 측에 안전하게 저장되며, 동시에 해시된 버전이 데이터베이스의 auth.refresh_tokens 테이블에도 저장된다. 액세스 토큰이 만료되었을 때, 클라이언트는 이 리프레시 토큰을 GoTrue 서버로 보내 새로운 액세스 토큰을 발급받는다.1

이 아키텍처는 순수 상태 비저장 방식의 단점(토큰이 탈취되었을 때 즉시 폐기할 수 없음)과 순수 상태 저장 방식의 단점(모든 요청마다 데이터베이스 조회가 필요하여 발생하는 성능 부하)을 효과적으로 절충한다. 리프레시 토큰을 데이터베이스에서 관리함으로써, 특정 사용자 세션을 서버 측에서 강제로 만료시키는 것이 가능해진다. 동시에 대부분의 API 요청은 빠른 상태 비저장 액세스 토큰으로 처리하여 시스템의 전반적인 성능을 유지한다.

4.2 Supabase JWT 페이로드 구조

Supabase가 발급하는 액세스 토큰의 페이로드는 표준 JWT 클레임과 Supabase 고유의 커스텀 클레임을 포함하여, RLS 정책에서 활용할 수 있는 풍부한 컨텍스트를 제공한다.34

주요 클레임은 다음과 같다.

  • sub: 사용자의 고유 ID (UUID). RLS 정책에서 auth.uid() 함수가 이 값을 반환한다.
  • role: 사용자가 데이터베이스에 접근할 때 부여받는 Postgres 역할. 기본적으로 authenticated 역할이 부여된다.
  • aal (Authenticator Assurance Level): 인증 보증 수준을 나타낸다. 비밀번호 등 1단계 인증만 완료하면 aal1이 되고, MFA(다중 인증)까지 완료하면 aal2가 된다. 이를 통해 MFA를 완료한 사용자에게만 특정 데이터 접근을 허용하는 정책을 만들 수 있다.
  • app_metadata: 애플리케이션 관리자만이 설정하고 수정할 수 있는 메타데이터 객체다. 사용자는 이 값을 직접 변경할 수 없으므로, 사용자의 역할(예: ‘admin’, ‘editor’), 구독 플랜 등 민감한 인가 관련 정보를 저장하기에 가장 적합한 공간이다.31
  • user_metadata: 사용자가 supabase.auth.updateUser() 함수 등을 통해 직접 수정할 수 있는 메타데이터 객체다. 사용자의 이름, 프로필 사진 URL, 개인 설정 등 보안과 무관한 정보를 저장하는 데 사용된다. 이 값은 사용자가 임의로 변경할 수 있으므로, RLS 정책의 조건으로 사용하는 것은 보안상 매우 위험하다.31

4.2.1 테이블: Supabase JWT 주요 클레임

이 테이블은 개발자가 RLS 정책을 작성하거나 서버에서 JWT를 검증할 때 어떤 정보를 활용할 수 있는지 명확하게 이해하는 데 필수적이다. 특히 app_metadatauser_metadata의 보안상 차이점을 인지하는 것이 매우 중요하다.

클레임타입설명RLS 활용 예시
substring (uuid)사용자의 고유 식별자. auth.uid() 함수가 이 값을 반환한다.(select auth.uid()) = user_id
rolestring사용자가 데이터베이스에 접근할 때 부여받는 Postgres 역할.TO authenticated
aalstring인증 보증 수준. MFA 완료 여부를 나타낸다.(auth.jwt()->>'aal') = 'aal2'
app_metadataobject관리자만 수정 가능. 사용자 역할, 구독 등 민감한 인가 정보 저장.(auth.jwt()->'app_metadata'->>'role') = 'admin'
user_metadataobject사용자 수정 가능. 프로필 정보 등 비보안 데이터 저장. RLS 정책에 사용 시 주의.사용 비권장 31

4.3 서버 사이드 렌더링(SSR)과 세션 관리

전통적인 클라이언트 사이드 애플리케이션(SPA)에서는 localStorage에 토큰을 저장하는 것이 일반적이지만, Next.js나 SvelteKit과 같은 SSR 프레임워크 환경에서는 서버와 브라우저 간에 인증 상태를 안전하고 효율적으로 공유하기 위해 쿠키 기반의 세션 관리가 필수적이다.27

이를 위해 Supabase는 @supabase/ssr이라는 별도의 라이브러리를 제공한다.27 이 라이브러리는 쿠키를 이용한 세션 관리의 복잡한 과정을 자동화한다. 작동 원리는 다음과 같다.

  1. 사용자가 로그인에 성공하면, 서버는 액세스 토큰과 리프레시 토큰을 HttpOnly, Secure 속성이 설정된 안전한 쿠키에 저장하여 클라이언트로 전송한다.
  2. 이후 브라우저는 모든 서버 요청에 이 쿠키를 자동으로 포함시킨다.
  3. 서버 측 코드(예: Next.js 미들웨어)는 각 요청에 포함된 쿠키에서 토큰 정보를 읽어 Supabase 클라이언트를 초기화한다.
  4. 만약 액세스 토큰이 만료되었다면, 서버는 쿠키에 담긴 리프레시 토큰을 사용하여 자동으로 새로운 액세스 토큰을 발급받고, 응답 헤더(Set-Cookie)를 통해 클라이언트의 쿠키를 최신 상태로 갱신한다.36

SSR 환경에서 보안을 위해 반드시 기억해야 할 점은, 서버 측 코드에서 supabase.auth.getSession() 대신 supabase.auth.getUser()를 사용해야 한다는 것이다. getSession()은 단순히 쿠키에 저장된 세션 정보를 읽어 반환하므로, 쿠키가 위변조되었을 경우 위험에 노출될 수 있다. 반면, getUser()는 매번 Supabase Auth 서버에 API 요청을 보내 토큰의 유효성을 다시 검증하므로, 사용자의 신원을 확실하게 보장할 수 있는 더 안전한 방법이다.36

5. 고급 기능 및 확장성

Supabase Auth는 기본적인 인증 및 인가 기능을 넘어, 각 애플리케이션의 고유한 비즈니스 로직에 맞게 시스템을 확장하고 커스터마이징할 수 있는 강력한 기능들을 제공한다.

5.1 커스텀 클레임과 역할 기반 접근 제어(RBAC)

Supabase는 ’인증 훅(Auth Hooks)’이라는 독창적인 메커니즘을 통해 인증 플로우를 확장할 수 있는 길을 열어준다.4 특히 ’Custom Access Token Hook’은 JWT가 발급되는 시점에 개발자가 정의한 PostgreSQL 함수를 실행하여, 동적으로 JWT 페이로드에 커스텀 클레임(Custom Claims)을 주입하는 기능이다.34

이를 이용한 역할 기반 접근 제어(RBAC) 구현 방법은 다음과 같다.

  1. 먼저, 사용자의 역할 정보(예: ‘admin’, ‘member’, ‘guest’)를 저장할 별도의 테이블(예: user_roles)을 데이터베이스에 생성한다.39
  2. 다음으로, JWT 발급 이벤트 정보를 인자로 받아 수정된 JWT 페이로드를 반환하는 PostgreSQL 함수를 작성한다. 이 함수는 user_roles 테이블을 조회하여 현재 사용자의 역할을 알아낸 뒤, 이 정보를 JWT의 app_metadata나 새로운 커스텀 클레임(예: user_role)에 추가하는 로직을 포함한다.41
  3. 마지막으로, Supabase 대시보드의 ‘Authentication > Hooks’ 설정 페이지에서 방금 작성한 PostgreSQL 함수를 ’Custom Access Token Hook’으로 등록한다.38

이렇게 JWT에 주입된 커스텀 클레임은 RLS 정책에서 auth.jwt() 함수를 통해 쉽게 접근하고 활용할 수 있다. 이를 통해 매우 정교하고 동적인 RBAC를 데이터베이스 수준에서 구현하는 것이 가능해진다.40

-- 'admin' 역할을 가진 사용자만 posts 테이블의 모든 행을 볼 수 있는 정책
CREATE POLICY "Admins can view all posts"
ON posts FOR SELECT
USING ( (auth.jwt()->'app_metadata'->>'role') = 'admin' );

Auth Hooks는 인증 로직의 중심을 데이터베이스로 가져오는 패러다임 전환을 이끈다. JWT 발급 시점에 DB 함수가 직접 호출되므로, 인증 관련 로직이 데이터베이스 트랜잭션 내에서 처리될 수 있다. 이는 인증과 데이터베이스 로직의 경계를 허물어, 데이터의 상태와 인증 상태 간의 실시간 일관성을 보장한다. 예를 들어, 사용자의 구독 상태가 subscriptions 테이블에서 만료되면, 다음 토큰 갱신 시점에 Auth Hook이 이를 즉시 감지하고 JWT에서 ‘premium’ 역할을 제거할 수 있다. 이는 외부 웹훅이나 별도의 동기화 프로세스 없이도 가능한, 매우 강력하고 효율적인 방식이다.

5.2 Edge Function을 이용한 인증 워크플로우 확장

Supabase Edge Functions는 Deno 런타임을 기반으로 하는 글로벌 분산 서버리스 함수로, 인증 관련 이벤트를 처리하고 외부 서비스와 연동하는 데 매우 유용하다.44 데이터베이스 웹훅(Database Webhooks)과 결합하여 강력한 자동화 워크플로우를 구축할 수 있다.

대표적인 사용 사례는 ’회원가입 후처리’이다. auth.users 테이블에 새로운 행이 INSERT될 때마다 특정 Edge Function을 호출하도록 데이터베이스 웹훅을 설정할 수 있다. 이 함수는 다음과 같은 작업을 수행할 수 있다.

  • 새로운 사용자를 위한 profiles 테이블 레코드 자동 생성
  • Resend나 SendGrid 같은 외부 이메일 서비스를 연동하여 개인화된 환영 이메일 발송 46
  • Salesforce나 HubSpot 같은 CRM 시스템에 새로운 사용자 정보 동기화 1

5.3 이메일 템플릿 및 SMTP 커스터마이징

Supabase는 인증 과정에서 사용자에게 발송되는 모든 시스템 이메일(회원가입 확인, 비밀번호 재설정, 매직 링크 등)의 내용과 디자인을 완벽하게 커스터마이징할 수 있는 기능을 제공한다.4

개발자는 Supabase 대시보드의 ‘Authentication > Email Templates’ 페이지에서 각 이메일 템플릿의 HTML 소스를 직접 편집할 수 있다.47 이 템플릿은 Go 템플릿 언어 문법을 따르며, {{.SiteURL }}, {{.ConfirmationURL }}, {{.Token }}, 그리고 user_metadata에 접근할 수 있는 {{.Data }}와 같은 동적 변수를 활용하여 개인화된 메시지를 구성할 수 있다.47

프로덕션 환경에서는 이메일 전달률과 신뢰도를 보장하기 위해 Supabase가 제공하는 기본 SMTP 서버 대신, SendGrid, Resend, AWS SES 등 전문 외부 SMTP 서비스를 연동하는 것이 강력히 권장된다. 이는 스팸 필터링을 피하고 브랜드의 신뢰도를 높이는 데 필수적인 과정이다.50

6. 보안 고려사항 및 구현 모범 사례

Supabase Auth의 강력한 기능들을 안전하게 활용하기 위해서는 몇 가지 핵심적인 보안 원칙을 반드시 준수해야 한다.

6.1 RLS의 전면적 활성화

가장 중요한 원칙은, 민감하거나 개인적인 데이터를 포함하는 모든 테이블에 대해 RLS를 활성화하는 것이다. 이는 선택 사항이 아니라 필수적인 보안 조치다.6 RLS가 비활성화된 테이블은 anon 키를 가진 모든 클라이언트에게 데이터가 그대로 노출될 수 있는 심각한 보안 취약점이 된다.51 Supabase 대시보드의 테이블 편집기를 통해 테이블을 생성하면 RLS가 기본적으로 활성화되지만, SQL 에디터로 직접 테이블을 생성할 경우에는 ALTER TABLE your_table_name ENABLE ROW LEVEL SECURITY; 구문을 수동으로 실행하여 RLS를 반드시 활성화해야 한다.6

6.2 API 키의 올바른 사용과 관리

Supabase는 두 종류의 주요 API 키를 제공하며, 이 둘의 역할을 명확히 구분하여 사용하는 것이 매우 중요하다.

  • anon (anonymous) 키: 이 키는 공개용으로, 클라이언트 사이드 코드(웹 브라우저, 모바일 앱)에 노출되어도 안전하도록 설계되었다. 이 키 자체는 어떠한 권한도 가지고 있지 않으며, 실제 데이터 접근 권한은 오직 RLS 정책에 의해서만 결정된다.52

  • service_role 키: 이 키는 비밀 키로, RLS를 포함한 모든 데이터베이스 보안 정책을 우회하는 최고 관리자 수준의 권한을 가진다. 따라서 이 키는 절대로 클라이언트 코드에 노출되어서는 안 되며, 오직 서버리스 함수나 별도의 백엔드 서버와 같이 안전하게 통제되는 서버 환경에서만 사용해야 한다.33

service_role 키는 환경 변수로 안전하게 관리하고, 코드에 직접 하드코딩하는 것을 피해야 한다.

6.3 비밀번호 정책 및 봇 탐지

사용자 계정의 보안을 강화하기 위해 Supabase 대시보드에서 강력한 비밀번호 정책을 설정해야 한다. 최소 비밀번호 길이를 8자 이상으로 설정하고, 숫자, 대소문자, 특수문자를 조합하도록 요구하는 것이 좋다. 또한, 유출된 비밀번호 사용 차단 기능을 활성화하여 사용자가 보안에 취약한 비밀번호를 사용하는 것을 방지해야 한다.16

로그인, 회원가입, 비밀번호 재설정 폼에는 CAPTCHA(hCaptcha 또는 Cloudflare Turnstile)를 통합하여 자동화된 봇에 의한 무차별 대입 공격(brute-force attack)이나 계정 생성 스팸을 효과적으로 방어할 수 있다.4

6.4 서버 사이드 인증의 중요성

민감한 데이터를 다루거나 중요한 비즈니스 로직을 수행할 때는 항상 서버 측에서 사용자의 세션을 다시 검증하는 절차를 거쳐야 한다. 클라이언트에서 전달된 JWT나 세션 정보를 맹목적으로 신뢰해서는 안 된다. Supabase Edge Functions나 Next.js 서버 컴포넌트와 같은 서버 환경에서는 supabase.auth.getUser() 함수를 사용하여 각 요청마다 사용자의 인증 상태와 토큰의 유효성을 Supabase Auth 서버에 직접 확인해야 한다. 이는 클라이언트 측에서 발생할 수 있는 토큰 조작이나 세션 하이재킹 공격으로부터 시스템을 보호하는 필수적인 방어 계층이다.36

7. 타 인증 솔루션과의 비교 분석 및 결론

Supabase Auth의 특징과 장단점을 명확히 이해하기 위해, 시장의 주요 경쟁 솔루션인 Firebase Authentication 및 Auth0와 비교 분석한다.

7.1 Supabase Auth vs. Firebase Auth

  • 아키텍처 및 데이터베이스: Supabase는 관계형 데이터베이스인 PostgreSQL을 중심으로 모든 기능이 통합된 반면, Firebase는 NoSQL 데이터베이스인 Firestore/Realtime Database와 인증 서비스가 별개로 운영되는 구조다.54 이 차이는 데이터 모델링과 쿼리 방식에 큰 영향을 미친다.
  • 인가 모델: Supabase는 SQL 기반의 RLS를 통해 데이터베이스 수준에서 직접적이고 정교한 인가 규칙을 적용한다. 반면, Firebase는 자체적인 JSON 기반의 보안 규칙(Security Rules) 언어를 사용하여 데이터베이스 접근을 제어한다.54
  • 가격 모델: Supabase는 월간 활성 사용자(MAU) 수를 기준으로 비교적 관대한 무료 등급과 예측 가능한 요금제를 제공한다.1 Firebase는 데이터 읽기/쓰기, 네트워크 사용량 등 세분화된 사용량 기반 요금제를 채택하고 있어, 트래픽이 급증할 경우 비용이 예기치 않게 증가할 수 있다.54
  • 오픈소스 및 벤더 종속성: Supabase는 모든 구성 요소가 오픈소스로 공개되어 있으며, 필요시 자체 호스팅이 가능하여 벤더 종속성에서 자유롭다. Firebase는 Google Cloud 생태계에 깊이 통합된 독점적(proprietary) 서비스로, 한번 도입하면 다른 플랫폼으로 이전하기 어렵다.1

7.2 Supabase Auth vs. Auth0

  • 제품 포지셔닝: Supabase Auth는 데이터베이스, 스토리지, 서버리스 함수 등을 포함하는 통합 백엔드 플랫폼(BaaS)의 핵심 구성 요소다. 반면, Auth0는 인증 및 신원 관리(IAM)에만 특화된 전문 솔루션(IDaaS)이다.57

  • 데이터베이스 통합: Supabase의 가장 큰 강점은 인증과 데이터베이스의 깊은 통합에 있다. Auth0는 인증 시스템이 애플리케이션의 주 데이터베이스와 완전히 분리되어 운영된다.1

  • 엔터프라이즈 기능: Auth0는 Okta에 인수된 이후, 복잡한 엔터프라이즈 요구사항(예: 고급 M2M 인증, 변칙 행위 탐지, 광범위한 SSO 프로토콜 지원)에 있어 Supabase보다 더 성숙하고 풍부한 기능을 제공한다.57 Supabase는 SAML 등을 지원하지만, 아직 Single Logout(SLO) 미지원이나

SCIM 자동 프로비저닝 부재 등 일부 엔터프라이즈 기능이 부족하다는 평가가 있다.10

  • 개발자 경험 및 가격: Supabase는 PostgreSQL에 익숙한 개발자에게 SQL을 활용한 코드 중심의 유연한 개발 경험을 제공하며, MAU당 비용이 훨씬 저렴하다.1 Auth0는 직관적인 대시보드 중심의 경험을 제공하지만, 복잡한 인가 모델을 구현하기 위해서는 자체적인 Rules나 Actions(JavaScript 코드)를 작성해야 하며, 전반적인 비용이 상대적으로 높다.1

7.2.1 테이블: 주요 인증 솔루션 비교

이 비교표는 프로젝트의 기술적, 비즈니스적 요구사항에 가장 적합한 인증 솔루션을 전략적으로 선택하는 데 도움을 주는 의사결정 도구다.

항목Supabase AuthFirebase AuthAuth0
핵심 아키텍처PostgreSQL 네이티브, 오픈소스Google Cloud 기반, NoSQL 중심클라우드 SaaS, 독점(Proprietary)
데이터베이스 통합최상. RLS를 통한 직접적인 통합보통. 보안 규칙으로 연동분리됨. 별도 동기화 필요
인가 모델PostgreSQL RLS (SQL 기반)Firebase Security Rules (자체 언어)RBAC, Rules, Actions (JavaScript 기반)
가격 모델MAU 기반, 예측 가능사용량 기반, 예측 어려움MAU 기반, 높은 가격대
자체 호스팅가능불가능불가능 (프라이빗 클라우드 제외)
개발자 경험코드 중심, SQL 친화적SDK 중심, Google 생태계 통합대시보드 중심, 높은 커스터마이징
주요 강점데이터 중심 보안, 오픈소스, 비용 효율성빠른 프로토타이핑, 모바일 SDK엔터프라이즈 기능, 광범위한 프로토콜 지원
주요 약점일부 고급 엔터프라이즈 기능 부족벤더 종속성, 복잡한 쿼리 한계높은 비용, 복잡한 인가 로직 구현 시 어려움

7.3 결론: Supabase 인증 시스템의 종합 평가 및 향후 전망

Supabase Auth는 PostgreSQL과의 깊은 통합을 기반으로 한 혁신적인 인증 및 인가 시스템이다. 특히 PostgreSQL의 행 수준 보안(RLS)을 핵심 인가 모델로 채택한 것은, 보안 로직을 데이터베이스 계층으로 중앙화하여 애플리케이션 코드를 단순화하고 일관성 있는 보안을 제공하는 강력한 패러다임을 제시한다. 개발자 친화적인 API, 오픈소스 기반의 유연성, 그리고 뛰어난 비용 효율성은 특히 스타트업과 중소 규모의 프로젝트에 매우 매력적인 선택지다.

다만, 복잡한 엔터프라이즈급 기능(예: 고급 감사 로그, SCIM 프로비저닝, 비기술 관리자를 위한 포괄적인 UI) 측면에서는 아직 Auth0과 같은 전문 솔루션에 비해 성숙도가 부족한 부분이 존재한다.10 향후 Supabase가 엔터프라이즈 시장으로 영향력을 확대하기 위해서는 이러한 기능들을 지속적으로 보강하고, 복잡한 RLS 정책의 성능 최적화에 대한 가이드를 더욱 강화할 필요가 있다.

그럼에도 불구하고, 인증과 데이터를 분리하지 않고 하나의 통합된 시스템으로 관리하려는 현대적인 개발 트렌드 속에서, Supabase Auth는 매우 유망하고 강력한 대안으로 확고히 자리매김하고 있다. 데이터 중심의 보안 모델을 추구하는 프로젝트에게 Supabase Auth는 타의 추종을 불허하는 독보적인 가치를 제공한다.

8. 참고 자료

  1. Supabase Auth: Build vs. Buy, https://supabase.com/blog/supabase-auth-build-vs-buy
  2. Auth architecture | Supabase Docs, https://supabase.com/docs/guides/auth/architecture
  3. Auth | Built-in user management - Supabase, https://supabase.com/auth
  4. Auth | Supabase Docs, https://supabase.com/docs/guides/auth
  5. Authorization via Row Level Security | Supabase Features, https://supabase.com/features/row-level-security
  6. Mastering Supabase RLS - “Row Level Security” as a Beginner - DEV Community, https://dev.to/asheeshh/mastering-supabase-rls-row-level-security-as-a-beginner-5175
  7. supabase.com, [https://supabase.com/docs/reference/self-hosting-auth/introduction#::text=The%20Supabase%20Auth%20Server%20(GoTrue,and%20authentication%20for%20JAM%20projects.](https://supabase.com/docs/reference/self-hosting-auth/introduction#::text=The Supabase Auth Server (GoTrue,and authentication for JAM projects.)
  8. supabase/auth: A JWT based API for managing users and issuing JWT tokens - GitHub, https://github.com/supabase/auth
  9. Self-Hosting Auth - Supabase, https://supabase.com/docs/reference/self-hosting-auth/introduction
  10. Supabase Auth Enterprise Features - SSOJet, https://ssojet.com/white-papers/supabase-auth-enterprise-features/
  11. GoTrue Auth Server - Supabase, https://zone-www-dot-9obe9a1tk-supabase.vercel.app/docs/gotrue/server/about
  12. Getting Started | Supabase Docs, https://supabase.com/docs/guides/getting-started
  13. JavaScript: Overview | Supabase Docs, https://supabase.com/docs/reference/javascript/auth-api
  14. REST API | Supabase Docs, https://supabase.com/docs/guides/api
  15. Password-based Auth | Supabase Docs, https://supabase.com/docs/guides/auth/passwords
  16. Password security | Supabase Docs, https://supabase.com/docs/guides/auth/password-security
  17. Social Login | Supabase Docs, https://supabase.com/docs/guides/auth/social-login
  18. Login with GitHub | Supabase Docs, https://supabase.com/docs/guides/auth/social-login/auth-github
  19. Login with Google | Supabase Docs, https://supabase.com/docs/guides/auth/social-login/auth-google
  20. Part Five: Google Oauth - Supabase Docs - Vercel, https://docs-n3gxhwtbf-supabase.vercel.app/docs/learn/auth-deep-dive/auth-google-oauth
  21. Identity Linking | Supabase Docs, https://supabase.com/docs/guides/auth/auth-identity-linking
  22. Passwordless email logins | Supabase Docs, https://supabase.com/docs/guides/auth/auth-email-passwordless
  23. Passwordless login via Magic Links | Supabase Features, https://supabase.com/features/passwordless-login-via-magicklink
  24. Supabase Magic Link Simplified for NextJS, https://nextjsstarter.com/blog/supabase-magic-link-simplified-for-nextjs/
  25. Login With Magic Link | Supabase Docs - Vercel, https://docs-204cjmxm5-supabase.vercel.app/docs/guides/auth/passwordless-login/auth-magic-link
  26. Building Phone Authentication with Supabase and Twilio in Flutter | by Muazzam Soomro, https://medium.com/@muazzamafaque/building-phone-authentication-with-supabase-and-twilio-in-flutter-1113da52c6a6
  27. Server-side Auth | Supabase Features, https://supabase.com/features/server-side-auth
  28. Redirect URLs | Supabase Docs, https://supabase.com/docs/guides/auth/redirect-urls
  29. Phone logins | Supabase Features, https://supabase.com/features/phone-logins
  30. Supabase.GoTrue — supabase_gotrue v0.5.2 - HexDocs, https://hexdocs.pm/supabase_gotrue/
  31. Row Level Security | Supabase Docs, https://supabase.com/docs/guides/database/postgres/row-level-security
  32. Easy Row Level Security (RLS) Policies in Supabase and Postgres - Max Lynch, https://maxlynch.com/2023/11/04/tips-for-row-level-security-rls-in-postgres-and-supabase/
  33. Best Practices for Securing and Scaling Supabase for Production Data Workloads | by firman brilian | Medium, https://medium.com/@firmanbrilian/best-practices-for-securing-and-scaling-supabase-for-production-data-workloads-4394aba9e868
  34. JSON Web Token (JWT) | Supabase Docs, https://supabase.com/docs/guides/auth/jwts
  35. JWT Claims Reference | Supabase Docs, https://supabase.com/docs/guides/auth/jwt-fields
  36. Setting up Server-Side Auth for Next.js | Supabase Docs, https://supabase.com/docs/guides/auth/server-side/nextjs
  37. Best Practices for Managing User Auth and Data in Supabase? - Reddit, https://www.reddit.com/r/Supabase/comments/1iziebu/best_practices_for_managing_user_auth_and_data_in/
  38. Custom Claims & Role-based Access Control (RBAC) | Supabase Docs, https://supabase.com/docs/guides/database/postgres/custom-claims-and-role-based-access-control-rbac
  39. Role-based Access Control (RBAC) User Authorization in Next.js - YouTube, https://www.youtube.com/watch?v=kwoKmi6inAw
  40. Building Role-Based Access Control (RBAC) with Supabase Row-Level Security - Medium, https://medium.com/@lakshaykapoor08/building-role-based-access-control-rbac-with-supabase-row-level-security-c82eb1865dfd
  41. 1월 1, 1970에 액세스, https.supabase.com/docs/guides/auth
  42. Custom Access Token Hook & RLS - help me make sense : r/Supabase - Reddit, https://www.reddit.com/r/Supabase/comments/1i5n8zd/custom_access_token_hook_rls_help_me_make_sense/
  43. How to set up custom claims in Supabase JWTs? - Bootstrapped, https://bootstrapped.app/guide/how-to-set-up-custom-claims-in-supabase-jwts
  44. Supabase Docs, https://supabase.com/docs
  45. Features | Supabase Docs, https://supabase.com/docs/guides/getting-started/features
  46. Custom Auth Emails with React Email and Resend | Supabase Docs, https://supabase.com/docs/guides/functions/examples/auth-send-email-hook-react-email-resend
  47. Email Templates | Supabase Docs, https://supabase.com/docs/guides/auth/auth-email-templates
  48. Supabase custom email templates for authentication flows with Shootmail email template builder | Template first email platform with scheduling and analytics. Made for developers, https://shootmail.app/blog/supabase-custom-email-templates-with-shootmail-email-template-builder
  49. Customizing Emails by Language - Supabase Docs, https://supabase.com/docs/guides/troubleshooting/customizing-emails-by-language-KZ_38Q
  50. Send emails with custom SMTP | Supabase Docs, https://supabase.com/docs/guides/auth/auth-smtp
  51. Securing your API | Supabase Docs, https://supabase.com/docs/guides/api/securing-your-api
  52. Securing your data | Supabase Docs, https://supabase.com/docs/guides/database/secure-data
  53. Best Security Practices in Supabase: A Comprehensive Guide - Supadex, https://www.supadex.app/blog/best-security-practices-in-supabase-a-comprehensive-guide
  54. Supabase vs Firebase, https://supabase.com/alternatives/supabase-vs-firebase
  55. 4 Best Firebase Alternatives for Scalable App Development [2025 Guide] - SuperTokens, https://supertokens.com/blog/firebase-alternatives
  56. 2025 Best Auth Providers: Top 5 Compared - Kinde, https://kinde.com/comparisons/top-authentication-providers-2025/
  57. Supabase vs Auth0, https://supabase.com/alternatives/supabase-vs-auth0
  58. Best Auth0 Alternatives & Competitors 2025 - Oso, https://www.osohq.com/learn/auth0-alternatives