인증 시스템 마이그레이션 — Supabase Auth에서 Firebase Auth로
마이그레이션 배경
초기 인증은 Supabase Auth를 썼다. DB, Storage, Auth를 한 플랫폼에서 관리했다. 그러다 JenaLab의 다른 서비스(Armo, Contexta)와 통합 인증이 필요해졌다. Supabase Auth의 한계가 드러났다.
Firebase Auth(shared-auth)를 선택한 이유:
| 기준 | Supabase Auth | Firebase Auth |
|---|---|---|
| 멀티 프로젝트 인증 | 프로젝트별 독립 | 단일 프로젝트로 통합 가능 |
| Google OAuth | 지원 | 네이티브 지원 + 간편 설정 |
| Admin SDK | 제한적 | 사용자 CRUD, 커스텀 클레임 완전 지원 |
| 모바일 SDK | 제한적 | Flutter/Swift/Kotlin 네이티브 |
JenaLab의 모든 서비스가 shared-auth 하나를 공유한다. 한 번 가입하면 모든 서비스를 쓸 수 있다.
마이그레이션 전략: 6단계 Phase
전체 교체를 한 번에 진행하지 않고, 6단계로 나누어 단계별로 빌드 검증을 수행했다.
Phase 1 환경변수 준비
Phase 2 의존성 설치
Phase 3 DB 스키마 변경 ← 가장 위험한 단계
Phase 4 Backend 인증 교체
Phase 5 Web 인증 교체
Phase 6 Admin 인증 교체
Phase 3: DB 스키마 변경 — 가장 위험한 단계
users.id의 타입이 바뀐다. Supabase Auth는 UUID다. Firebase Auth는 28자 영숫자 문자열이다.
-- 사용자 ID 타입을 uuid에서 text로 변경
-- 사용자를 참조하는 모든 FK 컬럼(9개 이상)도 함께 타입 변경
-- FK 제약을 일시 해제 후 재생성하는 과정이 필요
이 변경의 위험성:
- FK 제약 일시 해제 필요: 타입 변경 시 FK 제약을 DROP 후 재생성
- 기존 데이터 호환: 기존 UUID 데이터는 text로 자동 변환되지만, 새 Firebase UID와 형식이 다름
- 롤백 복잡도: text → uuid 역변환은 데이터 손실 위험
이 단계는 개발 DB에서 먼저 실행하고, 마이그레이션 SQL을 생성하여 코드 리뷰 후 운영에 적용했다.
Phase 4: Backend 인증 미들웨어 교체
// 변경 전: Supabase Auth — 토큰으로 사용자 조회 (네트워크 호출)
// 변경 후: Firebase Admin — JWT 로컬 검증 (네트워크 호출 없음)
verifyIdToken은 JWT를 검증하고 디코딩한다. 별도 네트워크 호출이 없다. 인증 레이턴시가 줄었다.
Phase 5: Web 클라이언트 인증
Web 앱은 Firebase의 클라이언트 SDK를 사용한다.
// Firebase 클라이언트 SDK 인증 흐름
// 1. 이메일/비밀번호 또는 Google OAuth로 로그인
// 2. 인증 상태 변경 감지 (onAuthStateChanged)
// 3. Firebase ID Token을 획득하여 API 요청에 사용
Supabase Auth는 쿠키 기반 세션이었다. Firebase는 클라이언트 사이드 토큰 관리 방식이다. Authorization: Bearer {token} 헤더로 Backend에 전달한다.
Supabase의 새로운 역할
인증을 Firebase로 이전한 후, Supabase의 역할이 명확해졌다.
┌─────────────────────────────────────────┐
│ Firebase │
│ Authentication (shared-auth) │
│ ID Token 발급 · 사용자 관리 │
└────────────────────┬────────────────────┘
│
┌────────────────────▼────────────────────┐
│ Supabase │
│ PostgreSQL · Realtime · (Storage*) │
│ *Storage는 이후 R2로 마이그레이션 │
└─────────────────────────────────────────┘
각 플랫폼이 가장 잘하는 영역만 담당하게 되었다.
Firebase 에러 메시지 한국어 처리
사용자 경험을 위해 Firebase 에러 코드를 한국어로 번역하는 함수를 구현했다.
// Firebase 에러 코드 → 한국어 메시지 매핑
// 예: 'auth/email-already-in-use' → '이미 등록된 이메일입니다.'
// 예: 'auth/wrong-password' → '비밀번호가 올바르지 않습니다.'
// 매핑되지 않은 코드는 기본 에러 메시지를 반환
교훈
- ID 타입은 유연하게: 외부 인증 시스템을 사용할 때
text타입이uuid보다 안전하다 - Phase별 빌드 검증: 대규모 마이그레이션은 반드시 단계별로 빌드를 확인한다
- 역할 분리: 하나의 플랫폼에 모든 것을 의존하면 마이그레이션 비용이 기하급수적으로 증가한다
다음 글에서는 같은 날 구현한 토스페이먼츠 구독 결제 시스템을 다룬다.