진짜 개발할 때 알아야 할 GoTrue의 핵심 기능들을 파헤쳐보자. 마케팅 헛소리 말고 실제로 코딩할 때 필요한 것들만.
아키텍처: 어떻게 돌아가는가?
GoTrue는 Kong API Gateway 뒤에서 돌아가면서 다음 컴포넌트들과 연동된다:

GoTrue 아키텍처 구조:
Client (브라우저/앱) → [Kong API Gateway](https://docs.konghq.com/) → [GoTrue Auth Service](https://github.com/supabase/auth) → [PostgreSQL DB](https://www.postgresql.org/)
↓
PostgREST (자동 API)
↓
Realtime (WebSocket)
핵심은 모든 인증이 PostgreSQL의 Row Level Security(RLS)와 연결된다는 점이다. 이게 다른 인증 서비스와의 가장 큰 차이점.
JWT 토큰과 RLS 연동: 이게 진짜 킬러 기능
-- 이렇게 하면 됨
CREATE POLICY "사용자는 자신의 데이터만 조회" ON profiles
FOR SELECT USING (auth.uid() = id);
-- JWT 토큰의 user_id가 자동으로 auth.uid()에 들어감
-- 별도 인증 로직 필요 없음!
진짜 개꿀이다. Express에서 매번 req.user.id
로 체크하던 그 귀찮은 일들이 데이터베이스 레벨에서 자동으로 처리된다.
지원하는 인증 방식들
1. 이메일/비밀번호
const { data, error } = await supabase.auth.signUp({
email: 'dev@example.com',
password: 'secure123!'
})
2. 매직링크 (비밀번호 없는 로그인)
const { data, error } = await supabase.auth.signInWithOtp({
email: 'dev@example.com',
options: {
emailRedirectTo: 'https://myapp.com/auth/callback'
}
})

3. 소셜 OAuth (카카오, 네이버, 구글 등)
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://myapp.com/auth/callback'
}
})
4. 전화번호 + SMS OTP
const { data, error } = await supabase.auth.signInWithOtp({
phone: '+821012345678',
})
5. 익명 로그인 (게스트 사용자)
const { data, error } = await supabase.auth.signInAnonymously()
실제 배포할 때 알아야 할 것들
환경변수 설정 (중요!)
## 기본 설정
GOTRUE_SITE_URL=https://myapp.com
GOTRUE_JWT_SECRET=your-super-secret-jwt-secret
GOTRUE_JWT_EXP=3600
## 데이터베이스
DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
## 이메일 발송 (SMTP)
GOTRUE_SMTP_HOST=smtp.gmail.com
GOTRUE_SMTP_PORT=587
GOTRUE_SMTP_USER=myapp@gmail.com
GOTRUE_SMTP_PASS=app-password
## 소셜 OAuth (구글 예시)
GOTRUE_EXTERNAL_GOOGLE_ENABLED=true
GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=your-google-client-id
GOTRUE_EXTERNAL_GOOGLE_SECRET=your-google-secret
GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=https://myapp.com/auth/callback
Docker로 배포하기

FROM supabase/gotrue:latest
COPY .env .env
EXPOSE 9999
CMD ["gotrue"]
근데 이 Docker 이미지가 ARM64 Mac에서 가끔 안 되는 경우가 있다. 그럴 때는 --platform linux/amd64
옵션 붙여서 실행하면 된다:
docker run --platform linux/amd64 -p 9999:9999 --env-file .env supabase/gotrue:latest
또는 Supabase CLI로 로컬에서 테스트:
npx supabase start
## 자동으로 GoTrue가 localhost:54321에서 실행됨
## 안 되면 Docker Desktop 실행되어 있는지 확인
첫 번째 실행할 때 Docker 이미지 다운받느라 한참 걸린다. 내가 측정해보니까 대충 20분은 걸렸나? 아니 내 인터넷이 느린 건가... 어쨌든 시간 오래 걸리니까 인내심 가져라. 그리고 RAM 8GB는 있어야 제대로 돈다. 내가 옛날 노트북에서 돌리다가 Docker Desktop 뻗고 블루스크린까지 떴다. 진짜 개빡쳤음.
한국 개발자들이 자주 하는 실수들
1. JWT Secret 관리

절대로 .env
파일을 git에 커밋하지 마라. JWT_SECRET
이 노출되면 누구나 가짜 토큰 만들 수 있다.
내가 한 번 .env
파일을 실수로 commit했더니 GitHub에서 20분 만에 "Secret detected in your repository"라는 제목으로 이메일이 왔다. 진짜 등골이 오싹했음. 바로 secret 갈아치우고 모든 토큰 무효화시켰는데, 사용자들이 다 로그아웃되면서 슬랙에 문의 메시지 폭탄 맞았다.
2. CORS 설정
## 이렇게 하면 안 됨 - localhost는 프로덕션에서 안 됨
GOTRUE_API_EXTERNAL_URL=localhost:9999
## 이렇게 해야 함
GOTRUE_API_EXTERNAL_URL=https://auth.myapp.com
이거 때문에 브라우저에서 Access to fetch at 'localhost:9999' from origin 'https://myapp.com' has been blocked by CORS policy
에러 뜨면서... 새벽 2시에 배포하다가 이 빨간 에러 보고 진짜 모니터 뒤질뻔했음. 온갖 Stack Overflow 글 다 뒤지고 Docker 재시작하고 .env 파일 100번 바꿔봤는데 결국 URL 설정이 문제였다.
3. RLS 정책 누락
PostgreSQL에서 RLS 활성화 안 하면 모든 데이터가 공개된다:
-- 필수! 모든 테이블에 설정해야 함
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- 정책도 꼭 만들어야 함 (이거 안 하면 아무것도 안 보임)
CREATE POLICY "Users can view own profile" ON profiles
FOR SELECT USING (auth.uid() = id);
이거 빼먹고 배포했다가 사용자 A가 사용자 B, C, D... 모든 사람의 개인정보를 다 볼 수 있는 개념탈선급 참사가 일어났다. 다행히 베타 유저 20명 정도였는데도 진짜 식은땀 범벅이었음. 1분도 안 되서 hotfix 배포했는데 그 1분이 1년 같았다.
4. Rate Limiting 설정 안함

무료 이메일 발송 할당량 금방 소진됨:
GOTRUE_RATE_LIMIT_EMAIL_SENT=60 # 시간당 이메일 60개로 제한 (현실적인 숫자)
내가 천재같이 무제한으로 설정했나? 그랬더니 어떤 악질이 스크립트 돌려서 몇 시간만에 SendGrid 무료 플랜 한도 다 털렸다. SendGrid에서 "Suspicious activity detected" 이메일 와서 계정 정지먹었고, 회원가입 이메일 인증이 안 되니까 서비스가 개박살났다. 토요일 저녁에 Resend로 갈아타느라 밤샜다.
성능과 확장성
성능은 어느 정도일까 (현실적으로)
- 동시 요청: 실제 프로덕션에서는 DB 병목이 먼저 와서 정확한 수치는 환경마다 다름
- JWT 검증: 빠르긴 한데 네트워크 지연이 더 큰 문제
- 데이터베이스 연결: Connection Pooling 덕분에 괜찮은 편. 근데 PostgreSQL 튜닝 안 하면 소용없음
프로덕션 배포 팁
## docker-compose.yml
version: '3.8'
services:
gotrue:
image: supabase/gotrue:latest
environment:
- GOTRUE_DB_MAX_POOL_SIZE=100 # DB 연결 풀 크기
- GOTRUE_RATE_LIMIT_HEADER=X-Forwarded-For # 로드밸런서 뒤에서 실행시
deploy:
replicas: 3 # 고가용성을 위한 멀티 인스턴스
모니터링 설정

## OpenTelemetry 메트릭 활성화
GOTRUE_METRICS_ENABLED=true
GOTRUE_METRICS_EXPORTER=prometheus
OTEL_EXPORTER_PROMETHEUS_PORT=9100
Grafana 대시보드와 Prometheus 연동하면 실시간 모니터링 가능하다.
마이그레이션: 기존 서비스에서 갈아타기
Auth0에서 GoTrue로

// 기존 Auth0 사용자 데이터 마이그레이션
const migrateUser = async (auth0User) => {
const { data, error } = await supabase.auth.admin.createUser({
email: auth0User.email,
email_confirm: true,
user_metadata: auth0User.user_metadata
})
}
[Firebase Auth](https://firebase.google.com/docs/auth)에서 GoTrue로
Firebase의 uid
를 GoTrue의 id
로 매핑하는 스크립트 필요. 공식 마이그레이션 가이드를 참고하자.
결론적으로, GoTrue는 개발자가 직접 제어할 수 있는 인증 시스템이 필요한 프로젝트에 최적이다. Auth0처럼 편하면서도 Firebase처럼 종속되지 않는 그 중간 지점을 제대로 찾은 솔루션이라고 보면 된다.