Actions
이슈 #434
진행중
JL
HP
[Go backport] Supabase GoTrue 인증 전환 — Phase 1: 인프라 + 인증 코어
이슈 #434:
[Go backport] Supabase GoTrue 인증 전환 — Phase 1: 인프라 + 인증 코어
시작일:
2026/05/11
완료일:
진척도:
0%
추정시간:
설명
배경¶
Rust 포팅(alphea-ai-edge)에서 진행된 Supabase GoTrue 인증 전환(#411, #421, #424) 과 관련 부속 작업(#375, #390, #256)을 원본 Go 프로젝트(alphea-rpc-next, branch next)로 백포트한다. 현재 프로젝트는 Rust 포팅을 중단하고 다시 Go 원본에서 예정 항목들을 진행하는 방향으로 복귀했다.
Phase 분할¶
본 이슈는 Phase 1 — 인프라 + 인증 코어 에 한정한다. 후속 phase 는 별도 이슈로 분리한다.
| Phase | 범위 | 이슈 |
|---|---|---|
| 1 (본 이슈) | GoTrue 인프라 + 표준 JWT + AuthContext user_id + 스키마 user_id 전환 + AuthService 축소 + Node/User/Wallet 핸들러 caller 전환 | 본 이슈 |
| 2 | AGX 회계 user_id 종속 전환 + wallet_adjustments ledger |
후속 (#421 백포트) |
| 3 | Admin Dev Console GoTrue Sign Up/Log In proxy + UI | 후속 (#424 백포트) |
Phase 1 작업 범위¶
인프라¶
-
alphea-rpc/docker-compose.yml에gotrue서비스 추가 (supabase/gotrue:v2.158.1, port9011) - Postgres init 스크립트 추가 (
db/init/01-gotrue-schema.sql):-
CREATE EXTENSION pgcrypto,uuid-ossp -
CREATE SCHEMA auth,GRANT ALL ON SCHEMA auth TO alphea - Supabase 표준 role 5개(
postgres,anon,authenticated,service_role,supabase_auth_admin)NOLOGIN으로 생성 +alphea에 멤버십 부여 (PG16+ grantor 요구사항)
-
-
.env.example정리:GOTRUE_URL,GOTRUE_INTERNAL_URL,GOTRUE_MAILER_AUTOCONFIRM,SITE_URL추가.AUTH_SALT/PASSWORD_SALT제거.
JWT 검증¶
- 비표준
SHA256(sigInput + secret)방식을 표준 HMAC-SHA256 으로 교체 (github.com/golang-jwt/jwt/v5) - GoTrue 발행 토큰 호환:
typclaim 없음 →token_type = "user" - Node 토큰:
typ = "node",sub = node_id유지 -
JWT_SECRET은 GoTrue 의GOTRUE_JWT_SECRET과 동일값 사용
AuthContext / 인터셉터¶
-
internal/server/interceptors.go의AuthContext에UserID(UUID),Email,TokenType추가 -
WalletFromContext→UserIDFromContext,NodeIDFromContext헬퍼 추가 - Public path allow-list 정리: 제거된 Auth RPC 제외, GoTrue proxy 경로 미포함(Phase 3)
DB 스키마 (v12 마이그레이션, clean rewrite)¶
-
accounts:user_id UUID UNIQUE컬럼 추가,email,display_name,profile_icon,last_active_at유지.wallet_address/password/account_type/referral_code는 deprecated 표시 (Phase 1 에서는 제거하지 않고 NOT NULL 제약 완화) -
wallets: 기존 (account_id, balance) 구조 폐기. 신규(user_id UUID, wallet_address TEXT)1:N.UNIQUE(user_id, wallet_address). 기존 데이터 DROP. -
nodes:owner_user_id UUID컬럼 추가,owner_wallet_address는 호환 위해 유지하되 더 이상 권한 판단에 사용 안 함 - 기존 wallet 식별 기반 dev 데이터 DROP 허용 (clean rewrite)
AuthService 축소 (proto)¶
-
auth.proto에서 다음 RPC 완전 제거:-
Challenge,Verify,SetPassword,Login,EmailRegister,EmailRecover
-
- 유지:
GenerateKeypair - 관련 메시지 타입 제거 (
ChallengeRequest/Response,VerifyRequest,LoginRequest,EmailRecoveryRequest/Response,SetPasswordRequest/Response) -
handler/auth.go단순화 -
internal/domain/auth/challenge.go는 노드 등록 챌린지 용도로 유지 (NodeService.NodeChallenge 만 사용)
NodeService¶
-
NodeChallenge:owner_wallet_address요청 필드 제거(또는 무시) -
RegisterNode: user JWT 필수,owner_user_id= JWT sub UUID 로 저장 -
Heartbeat/DeleteNode:owner_user_id기준 소유권 검증 -
ConnectNode: node 토큰 검증 흐름 유지. token 의sub는 node_id (또는 owner user_id) 와 노드 헤더 일치 확인
UserService¶
-
GetUser(wallet_address)→wallets테이블에서 user_id 조회 →accounts조회. 미존재 시NOT_FOUND - friend_count 계산은 기존 friends 테이블 그대로 사용 (Phase 2 에서 user_id 기반 재설계)
WalletService¶
- 모든 RPC: caller user_id 로 본인 소유 wallets 확인. 요청의 wallet_address 가 caller 의 wallets 에 속하지 않으면
PermissionDenied - 잔액/수익 계산 로직 자체는 Phase 2 에서 처리. Phase 1 에서는 인증 흐름만 전환하고 기존 wallet_address 기반 receipts 합산 유지.
마이그레이션 전략¶
-
Clean rewrite — Rust 측과 동일. dev/qa DB 는 reset 필요.
scripts/ec2/reset-db.sh와 호환. - 기존 wallet challenge/verify 로 만들어진 accounts/wallets/nodes dev 데이터는 마이그레이션 시 DROP.
- 운영(
prod) 에는 본 phase 미적용 (브랜치는next한정).
DoD¶
-
GoTrue 가
docker compose up으로 정상 기동(Listening on :9011, autoconfirm=true) -
Postgres init script 가
pgcrypto/uuid-ossp/authschema + supabase role 5종 생성 -
GoTrue 발행 access_token 으로
Authorization: Bearer <jwt>헤더 보내면WalletService/GetReceipts등 보호 RPC 통과 -
AuthContext.UserID가 GoTruesub(UUID) 와 일치 -
NodeService.RegisterNode가 user JWT 없으면 거부 -
NodeService.Heartbeat/DeleteNode가 다른 사용자 노드 조작 시PermissionDenied -
UserService.GetUser(wallet)가walletsjoin 으로 정상 조회 -
make build,make test통과 -
auth.proto에서 제거된 RPC 들에 대한 클라이언트 호환성은 본 phase 에서 보장하지 않음 — 클라이언트 마이그레이션은 모바일 SDK 측에서 별도 처리
관련 이슈¶
JL James Lee이(가) 6달 전에 변경
- 상태을(를) 신규에서 해결(으)로 변경되었습니다.
Phase 1 구현 완료¶
commit:server|03c6c64
Rust 측의 #411 / #421 (일부) / #424 (인프라 부분) / #375 / #390 결과를 원본 Go 프로젝트 alphea-rpc-next 의 next 브랜치로 백포트. 쓰기 시점의 목표는 GoTrue UUID 일니티를 권위로 세우고 기존 wallet challenge 흐름을 완전히 교체하는 것.
적용된 변경¶
인프라
-
alphea-rpc/docker-compose.yml에supabase/gotrue:v2.158.1서비스 추가 (포트 9011,GOTRUE_JWT_SECRET=$JWT_SECRET,MAILER_AUTOCONFIRM=true) -
alphea-rpc/db/init/01-gotrue-schema.sql가 Postgres 최초 기동 시pgcrypto/uuid-ossp확장,auth스키마, Supabase 표준 role 5종(postgres/anon/authenticated/service_role/supabase_auth_admin) 를 생성하고alphea로에 멤버십 부여 (PG16+ grantor 요구사항 충족) -
.env.example에GOTRUE_URL/GOTRUE_INTERNAL_URL/GOTRUE_PORT/GOTRUE_MAILER_AUTOCONFIRM/SITE_URL추가
JWT 검증
-
internal/domain/auth/jwt.go가 기존 비표준SHA256(sigInput + secret)를 버리고github.com/golang-jwt/jwt/v4기반 표준 HS256 구현으로 교체. GoTrue 발행 토큰(typ없음,sub=UUID) 과 자체 발행 노드 토큰(typ="node",sub=node_id) 동일 경로로 검증
서버 인터셉터
-
internal/server/interceptors.go의 토큰 컨텍스트를 구조체로 재설계:AuthContext{UserID, NodeID, Email, TokenType, Wallet}, 헬퍼UserIDFromContext/NodeIDFromContext/AuthFromContext추가. 기존WalletFromContext는 하위 호환을 위해 유지(deprecated) -
AuthInterceptor의 verify 시그니쳐를VerifyFunc func(token) (*AuthContext, error)로 일반화, public allow-list 에서 제거된 Auth RPC 목록 정리
Proto / Handler
-
auth.proto를 GenerateKeypair 한 개만 남기도록 축소. Challenge / Verify / SetPassword / Login / EmailRegister / EmailRecover RPC 와 관련 메시지 제거 -
node.proto:NodeChallengeRequest.owner_wallet_address제거.RegisterNodeRequest.owner_wallet_address→wallet_address(서명 검증용 키페어 주소로 의미 주석 부여, 소유권은 JWT 기반) -
handler/auth.go는 GenerateKeypair +VerifyToken헬퍼만 유지 -
handler/node.go:RegisterNode가 user JWT 필수, 서명 검증 후nodes.owner_user_id에 caller UUID 바인딩. 이미 다른 user 에게 소유권이 있으면PermissionDenied.Heartbeat와ConnectNode가 user/node 권한 분기 검증 (requireNodeAccess) -
ConnectNode는 추가로 토큰의sub가X-Node-ID헤더와 일치하는지도 확인
스토어
-
internal/store/migrations.go에 v12 추가:accounts.user_id UUID UNIQUE/accounts.display_name컬럼 추가,wallet_address/account_typeNULL 허용으로 완화.nodes.owner_user_id UUID컬럼 + 인덱스. accounts / wallets / friends / referral_claims / rewards_log / nodes 와wallet_comments를 TRUNCATE (clean rewrite 정책 — dev/qa DB 는 reset 필요) -
internal/store/accounts.go에Account.UserID *string/Account.DisplayName *string추가,scanAccount를sql.NullString기반으로 교체.GetAccountByUserID/EnsureAccountForUser헬퍼 추가 -
internal/store/nodes.go는Node.OwnerUserID *string으로 확장,RegisterNodeForUser헬퍼 (UPDATE 후 더 이상 없으면 INSERT) 추가
테스트
-
handler/node_test.go에 새 인증 모델 기준의 테스트 2개: 익명 요청의 Unauthenticated, user JWT 헤더 포함 시 owner_user_id 바인딩 검증. 기존 wallet-identity 기반 테스트 제거 -
handler/test_helpers.go로 공용uniqueTestWallet도우미 헬퍼 이동 -
auth_test.go는 제거된 RPC 들을 테스트하므로 삭제. JWT 검증 단위 테스트 4개가jwt_test.go에 남아 GoTrue 스타일 토큰과 노드 토큰을 모두 검증
문서
-
CLAUDE.mdKey Implementation Notes 업데이트: GoTrue / 표준 HMAC-SHA256 / accounts.user_id / nodes.owner_user_id / AuthService 축소 반영, 환경변수 표에 GoTrue 관련 항목 추가
DoD 체크¶
-
GoTrue 가 docker compose 로 기동하도록 설정 (실제 적용은 dev DB reset 후
docker compose up -d --build필요) - Postgres init script 가 pgcrypto/uuid-ossp/auth schema + supabase role 5종 생성
-
서버가 GoTrue 발행 JWT 를 표준 HS256 경로로 검증 (
go test ./internal/domain/auth통과) -
AuthContext.UserID가 GoTruesubUUID 와 일치하는 구조 확립 -
RegisterNode가 user JWT 없으면 Unauthenticated 거부, 있으면 owner_user_id 바인딩 -
Heartbeat/ConnectNode가 owner/node 일치 불일치 시 PermissionDenied -
go build ./...,go vet ./...,go test ./...통과 (PG 통합 테스트는 TEST_DATABASE_URL 미설정으로 skip) -
auth.proto에서 제거된 RPC 들은 wire 호환성 보장하지 않음 (모바일 SDK 측 마이그레이션은 별도 이슈)
후속 (이번 범위 완)¶
CP Chris Park이(가) 6달 전에 변경
- 담당자을(를) James Lee에서 Henry Park(으)로 변경되었습니다.
Actions