나의 구축 순서와 인증 설정 · 별도 원문
본문의 관련 교시에서 연결한 선택 심화다. 각 항목 끝의 교시 링크로 발표와 교재에 돌아갈 수 있다.
목차와 처음으로 ↑Codex에서 시작해 GitHub에 기록하고, Supabase·Vercel·Resend와 SNS 인증을 연결하는 실습 중심 강의.
본문의 관련 교시에서 연결한 선택 심화다. 각 항목 끝의 교시 링크로 발표와 교재에 돌아갈 수 있다.
목차와 처음으로 ↑Codex에서 구현하고 GitHub에 기록한 뒤 DB·공개 앱·메일·SNS를 연결한다.
요구·로컬 구현·검증
branch·commit·PR
DB·Auth·RLS
URL·환경·배포
가입·복구 메일
Google·Naver·Kakao
이 순서는 최초 구축의 이해를 돕는다. 실제 개발에서는 DB와 화면을 오가며 반복한다. 공개 URL을 만든 뒤 메일·OAuth 복귀 주소를 다시 맞추고 통합 검증한다. 도구 선택 자체가 보안과 로그인 완료를 보장하지 않는다.
작은 요구를 구현하고 검토 가능한 기록으로 남긴다.
현재 저장소의 문서와 구조를 먼저 읽고 미니 교육 포털의 구현 계획을 작성해줘. 목록·본인 신청·가입·로그인·복구·내보내기를 작은 작업으로 나눠줘. 각 작업의 변경 파일, 데이터와 권한, 검증 방법을 적어줘. 구현 후 diff와 실제 확인 범위를 남기고 다음 단계와 구분해줘.PostgreSQL·Auth·Storage와 프로젝트의 키를 구분한다.
DB 비밀번호는 PostgreSQL 접속 자격이다. 이용자의 로그인 비밀번호와 다르다. 현재 신규 테이블의 Data API 노출이 자동이라고 가정하지 않는다. GRANT는 테이블에 할 수 있는 작업, RLS는 접근 가능한 행을 제한한다. SQL Editor의 관리자 권한만으로 RLS를 검증하지 않는다.
화면에 보이는 옵션과 서버·DB가 강제할 조건을 함께 정한다.
| 영역 | 설정·설계 | 검증 |
|---|---|---|
| 이메일 가입 | 공개 가입/초대 전용 중 요구에 맞게 선택 | 정책 밖 가입 거부 |
| 확인·세션 | 이메일 확인·SSR 쿠키 갱신 | 미확인·새로고침·로그아웃 |
| 비밀번호 | 길이·유출 방지·재인증 제공 범위 확인 | 약한 비밀번호 거절 |
| DB | 테이블 권한·RLS·소유권 | 다른 계정 직접 요청 거절 |
| 역할 | 서버 관리 역할·승인 상태 | 버튼·user_metadata로 승격 불가 |
| 메일·요청 | SMTP·빈도 제한·필요시 CAPTCHA | 중복·남용·오류 안내 |
유출 비밀번호 방지는 현재 Pro 이상 제공 여부를 확인한다. 길이 정책은 수업 예시로12자 이상을 선택할 수 있으나 제품 기본값이라고 말하지 않는다. 관리자 계정 보호와 앱 이용자 MFA를 구분한다.
모든 키를 Vercel에 복사할 필요는 없다.
| 항목 | 보관 위치 | 브라우저 공개 |
|---|---|---|
| Supabase URL·publishable key | 앱 환경변수 | 가능 · RLS 전제 |
| DB 비밀번호·secret/service_role | 필요한 서버·비밀관리 | 불가 |
| Resend SMTP API key | Supabase Auth SMTP Password | 불가 |
| 앱 알림용 RESEND_API_KEY | 메일 API를 호출할 서버 환경 | 불가 |
| SNS Client Secret | Supabase provider 설정 | 불가 |
| 사이트 URL·기능 플래그 | 앱 환경별 설정 | 용도에 따라 |
Supabase Auth만 Resend SMTP로 메일을 보내면 앱 서버에 Resend API key가 필요하지 않다. 별도 알림 API를 직접 호출할 때만 서버 키를 둔다. 공개키는 사용자 권한을 대신하지 않는다.
공개 URL과 서버 설정을 실제 배포에 연결한다.
Docker로 로컬 Supabase를 썼다는 이유로 그 컨테이너가 Vercel에서 자동 실행되는 것은 아니다. DB는 Supabase Cloud 등 별도 서비스로 연결한다. 생성도구에서 가져온 앱은 Vercel 런타임 호환성을 별도 확인한다.
발송 도메인 검증을 수업 전에 끝낸다.
레코드의 실제 이름과 값은 계정의 Resend 화면에서 복사한다. 기존 도메인 메일 수신과 인증 메일 발신의 DNS 목적이 다를 수 있다. DNS 전파와 검증 대기 시간은 강의실 실습에서 제외한다.
메일을 발행하는 Auth와 전달하는 Resend를 연결한다.
| SMTP 항목 | 수업 설정 | 의미 |
|---|---|---|
| Host | smtp.resend.com | Resend SMTP 서버 |
| Port | 465 | TLS SMTP 예시 |
| Username | resend | SMTP 사용자 이름 |
| Password | 전용 Resend API key | Supabase DB 비밀번호와 다름 |
| Sender email | 검증한 도메인의 발신 주소 | 실제 전달 주체 |
| Sender name | 수업 서비스 이름 | 수신함 표시 이름 |
주소 세 종류의 목적을 구분한다.
| 항목 | 예시 | 역할 |
|---|---|---|
| Site URL | https://course.example.org | 앱 기본 주소·기본 복귀 |
| Supabase Redirect URLs | https://course.example.org/auth/callback | 앱이 요청할 복귀 허용 목록 |
| 복구 화면 | https://course.example.org/auth/update-password | 복구 세션 후 새 비밀번호 입력 |
| 이메일 확인 경로 | 앱이 구현한 /auth/confirm 등 | token_hash와 type 검증 방식 |
| OAuth 공급자 callback | https://PROJECT_REF.supabase.co/auth/v1/callback | 외부 제공자가 Supabase로 돌아옴 |
각 경로는 예시이므로 코드와 메일 템플릿의 실제 구현에 맞춘다. Site URL 하나를 바꾸어도 모든 템플릿과 명시적 redirectTo가 자동으로 바뀌는 것은 아니다. 스테이징은 별도 앱 주소·Supabase ref로 관리한다.
사용자가 출발하는 인증 상태가 다르다.
| 상황 | 시작 | 완료 |
|---|---|---|
| 일반 가입 | 이메일·비밀번호 입력 | 이메일 확인과 앱 가입 조건 완료 |
| 초대 후 최초 설정 | 관리자가 발행한 유효 초대 | 초대 검증·본인 비밀번호 설정 |
| 일반 로그인 | 확인된 계정·비밀번호 | Auth 세션·업무 권한 확인 |
| 로그인 후 비밀번호 변경 | 유효 세션·필요시 재인증 | 새 비밀번호 저장 |
| 비밀번호 분실 | 복구 요청·실제 메일 | 복구 검증·변경·새 로그인 |
이용자 비밀번호는 Supabase Auth가 관리한다. 앱 테이블에 평문이나 자체 비밀번호 열을 만들지 않는다. 학교 포털 비밀번호·DB 비밀번호·SMTP Password와 같은 비밀번호라고 가르치지 않는다.
요청 성공에서 멈추지 않고 새 비밀번호 로그인까지 확인한다.
resetPasswordForEmail
Resend·수신함
템플릿과 맞는 교환
검증된 사용자
updateUser
변경 결과 확인
요청·처리·배달·링크·세션을 나누면 원인을 찾기 쉽다.
| 지점 | 확인할 것 |
|---|---|
| Auth 요청 | 요청 종류·오류·빈도 제한·confirm 설정 |
| SMTP 처리 | host·port·자격·도메인·발신 주소 |
| 전달·수신 | Resend 이벤트·반송·스팸함·메일 정책 |
| 메일 링크 | 앱 주소·만료·재사용·보안 스캐너 |
| 앱 세션 | 쿠키·교환·returnTo·환경별 키 |
Resend의 처리 성공과 받은 편지함 도착, 링크 확인과 로그인은 서로 다르다. 미발송을 성공으로 표시하거나 자동 이메일 확인으로 우회하지 않는다. 발송 자격을 확인한 것만으로 실제 회원 메일 도착을 주장하지 않는다.
SMTP 자격 확인과 최종 사용자 검증을 구분한 기록이다.
출처: uc-anchor/docs/04-report/preview-resend-smtp.report.md 및 docs/02-design/features/preview-resend-smtp.design.md. 구 지역 Preview와 후속 서울 staging의 기록을 섞지 않는다. 프로젝트 ref·키·개인 메일을 수업용 설정으로 복사하지 않는다.
기본 메일과 Custom SMTP의 제공 범위를 구분한다.
외부 계정 인증 뒤 Supabase 세션과 앱 가입 상태를 확인한다.
signInWithOAuth
본인 인증·정보 동의
외부 code·토큰 처리
PKCE 세션 교환
이메일·동의·프로필
서버 역할·RLS
제공자 Redirect URI는 Supabase 대시보드의 callback을 복사한다. 앱 callback은 Supabase 이후 돌아갈 주소다. 로그인 버튼 선택은 강사·관리자 역할 부여가 아니다. 앱 동의와 제공자 정보 동의도 별도로 관리한다.
Google OAuth Client를 Supabase Google 제공자에 등록한다.
승인된 JavaScript origin은 사용한 Google 클라이언트 방식이 요구할 때 등록한다. 불필요한 Drive·Calendar 접근은 요청하지 않는다. u-livet의 openid email 축소는 앱이 queryParams로 인가 URL을 조정한 프로젝트 구현이므로 기본 SDK 동작으로 단정하지 않는다.
REST API 키와 카카오 로그인 설정을 Supabase에 맞춘다.
REST API 키, JavaScript 키, Admin 키는 역할이 다르다. 수업에서 이메일이 항상 제공된다고 가정하지 않는다. provider 설정만 켠 상태와 앱의 실제 사용 가능 상태를 구분한다.
u-livet은 custom:naver와 서버 userinfo 어댑터를 사용한다.
| 항목 | 설정 예시 |
|---|---|
| 제공자 유형 | OAuth2 · identifier naver |
| 앱 provider 값 | custom:naver |
| Authorization | https://nid.naver.com/oauth2.0/authorize |
| Token | https://nid.naver.com/oauth2.0/token |
| 원본 userinfo | https://openapi.naver.com/v1/nid/me |
| Supabase userinfo | 내 서버의 검증·평탄화 어댑터 URL |
Naver는 여기서 OIDC discovery/JWKS가 아닌 OAuth2 경로다. Supabase Custom OAuth 제공 범위·quota·email_optional 지원을 계정에서 확인한다. 브라우저가 보내는 임의 사용자 JSON을 신뢰하지 않는다.
외부 identity를 유지하며 앱에서 요구할 이메일을 실제 확인한다.
// 합성 사용자 정보 변환 예시
{
"sub": "synthetic-naver-user-001",
"email": "learner@example.invalid",
"email_verified": false
}실제 후속 기록은 별도 무저장 클라이언트의 이메일 OTP 검증 후 원 OAuth 세션을 갱신한다. 초보자가 OTP 로그인으로 기존 세션을 덮어쓰는 것을 피하도록 강사 기준 구현을 사용한다. 기존 대화·문서에도 개인 계정 전체 가입 완료는 별도 확인으로 남은 범위가 있으므로 모의 검사와 구분한다.
추가 인증 강도와 데이터 소유권을 동시에 검사한다.
AAL2는 인증 강도이며 관리자 역할이 아니다. QR·비밀키·인증코드를 URL·로그·영구 브라우저 저장에 남기지 않는다. factor 등록만으로 검증이 끝난 것은 아니다. 실제 복구 운영은 승인된 계정 복구 절차로 연결한다.
정상 결과와 실패 결과를 같은 표에 남긴다.
| 조건 | 행동 | 기대 결과 |
|---|---|---|
| 방문자 | 보호 API 직접 호출 | 거부 |
| 계정 A | 저장·새로고침·본인 수정 | 동일 본인 기록 |
| 계정 B | A 기록 조회·수정·삭제 | 거부 또는 0행 |
| SNS 신규·기존 | 최초 가입·취소·재로그인 | 정해진 가입 상태·동일 identity |
| 복구 메일 | 만료·사용한 링크·변경 후 로그인 | 올바른 거절과 새 비밀번호 |
| MFA 전후 | 보호 내보내기 직접 요청 | 전:거부 / 후:본인만 허용 |
SQL Editor 관리자 결과만으로 사용자 RLS 통과를 선언하지 않는다. 수신함을 보지 않은 메일 항목이나 실제 SNS 계정에서 실행하지 않은 항목은 미확인으로 남긴다.
설정은 Git에 모두 들어 있지 않다.
한 단계의 성공이 다음 단계를 자동으로 증명하지 않는다. Git의 소스 변경과 hosted Auth 설정은 서로 다른 이력이다. 환경별 체크표에 값 대신 이름·대상·확인 시각만 기록한다.
다음 사람이 실행·검증·복구할 수 있게 기록한다.
실제 확인한 결과만으로 운영 README를 작성해줘. Codex·GitHub·Supabase·Vercel·Resend·SNS 제공자별 역할, 환경별 설정 이름, 실행과 검증, 비밀번호와 MFA 안내, 장애 확인 순서를 넣어줘. 키·토큰·개인정보는 제외해줘. 코드 배포·DB·Auth/SMTP·외부 제공자 설정의 복구 범위와 미확인 항목을 명시해줘.