# 로빙 프로젝트 인증 시스템 전체 분석 및 통합 방안 ## 현재 구조 분석 ### 1. 데이터베이스 (PostgreSQL - auth_db) #### Users 테이블 구조 ```sql - id: UUID (Primary Key) - username: VARCHAR(50) UNIQUE # happybell80 등 - email: VARCHAR(255) UNIQUE NOT NULL - name: VARCHAR(255) - picture: VARCHAR(500) # OAuth profile picture URL - oauth_provider: VARCHAR(50) # google, github 등 - oauth_id: VARCHAR(255) # Provider의 user ID - is_active: BOOLEAN - created_at, updated_at, last_login_at: TIMESTAMP ``` #### WorkspaceMembers 테이블 ```sql - user_id: UUID (FK to users.id) - workspace_id: UUID - robing_id: VARCHAR(100) # rb8001, rb10508 등 - role: ENUM (owner, member, guest) ``` ### 2. Auth Server (51123 서버, 포트 9000) #### JWT 토큰 구조 ```python # 토큰 생성 시 페이로드 (gmail.py:183-188) { "sub": username, # "happybell80" - 주요 식별자 "email": user_email, # "goeun2dc@gmail.com" "name": user_name, # "김고은" "username": username, # "happybell80" (중복) "exp": expires_at } ``` #### 환경 변수 - JWT_SECRET_KEY: `ro-being-auth-jwt-secret-key-2024` - JWT_ALGORITHM: `HS256` - JWT_ACCESS_TOKEN_EXPIRE_MINUTES: 30일 #### 이메일-유저명 매핑 (하드코딩) ```python # gmail.py:150-154 email_to_username = { 'goeun2dc@gmail.com': 'happybell80', 'eagle0914@gmail.com': 'eagle0914', } ``` ### 3. Frontend (frontend-customer) #### 토큰 저장/조회 - **저장 키**: `auth_token` (auth-context.tsx:61) - **조회**: `localStorage.getItem('auth_token')` (auth-context.tsx:29) - **서버 URL**: `https://auth.ro-being.com` (하드코딩) #### 현재 문제점 ```typescript // robing-api.ts - 토큰 전송 안함! export async function sendMessage(text: string, userId: string = 'test_user') { // Authorization 헤더 없음 // 모든 사용자가 'test_user'로 처리됨 } ``` ### 4. Robing Gateway (포트 10100) #### 현재 처리 방식 ```python # main.py:92-95 x_user_id: Optional[str] = Header(None) # X-User-Id 헤더만 확인 # JWT 토큰 검증 없음! ``` ### 5. Robing Services (51124 서버) #### ChromaDB 컬렉션명 생성 ```python # storage.py:84 (추정) collection_name = f"{robing_id}_{user_id}_episodic" # 현재: rb10508_test_default_episodic (모든 사용자 공유!) ``` ## 주요 문제점 ### 1. 인증 토큰 미전송 ⚠️ - Frontend가 API 호출 시 JWT 토큰을 전송하지 않음 - `robing-api.ts`에 Authorization 헤더 없음 - 모든 사용자가 'test_user'로 처리 ### 2. 백엔드 토큰 미검증 ⚠️ - Robing Gateway가 JWT 토큰을 검증하지 않음 - X-User-Id 헤더만 확인 (누구나 위조 가능) ### 3. 사용자 식별 실패 ⚠️ - username이 제대로 전달되지 않아 'default'로 폴백 - ChromaDB 컬렉션을 모든 사용자가 공유 ### 4. 이메일-유저명 매핑 하드코딩 📝 - 새 사용자 추가 시 코드 수정 필요 - 확장성 없음 ### 5. OAuth 권한 과다 요청 🔐 - 회원가입/로그인 시 Gmail 읽기/쓰기 권한(`gmail.modify`)까지 요청 - 복잡한 동의 과정으로 사용자 이탈 가능성 높음 - 이메일 기능 미사용자에게도 과도한 권한 요청 ### 6. 변수명 불일치 혼란 🔄 - user_id vs username vs email 혼용 - JWT의 'sub'가 username인지 user_id인지 불명확 ## 결정 필요 사항 ### 1. 주요 식별자 선택 - [ ] **username** (추천): 'happybell80' - 인간 친화적, URL 안전 - [ ] **user_id (UUID)**: 'a1b2c3d4-...' - DB 표준, 중복 없음 - [ ] **email**: 'goeun2dc@gmail.com' - OAuth 표준, 변경 가능성 ### 2. JWT 페이로드 표준화 ```json 옵션 A (username 중심): { "sub": "happybell80", // 주 식별자 "user_id": "uuid-here", // DB ID "email": "goeun2dc@gmail.com", "name": "김고은" } 옵션 B (UUID 중심): { "sub": "uuid-here", // 주 식별자 "username": "happybell80", "email": "goeun2dc@gmail.com", "name": "김고은" } ``` ### 3. API 헤더 표준화 ``` 옵션 A (Bearer 토큰만): Authorization: Bearer 옵션 B (Bearer + X-User-Id): Authorization: Bearer X-User-Id: happybell80 // 빠른 조회용 옵션 C (Bearer + X-Username): Authorization: Bearer X-Username: happybell80 // 명확한 이름 ``` ### 4. ChromaDB 컬렉션 네이밍 ``` 옵션 A: {robing_id}_{username}_episodic 예: rb10508_happybell80_episodic 옵션 B: {robing_id}_{user_uuid}_episodic 예: rb10508_a1b2c3d4_episodic 옵션 C: {workspace_id}_{robing_id}_{username}_episodic 예: workspace1_rb10508_happybell80_episodic ``` ### 5. 토큰 저장 키 통일 ```javascript 현재: 'auth_token' 대안: 'jwt_token', 'access_token', 'robing_token' ``` ### 6. OAuth 권한 분리 전략 ```python # 옵션 A: 단계별 권한 요청 (추천) ✅ 기본 로그인: openid, userinfo.email, userinfo.profile 이메일 스킬: gmail.modify (별도 연결) 캘린더 스킬: calendar.events (별도 연결) # 옵션 B: 일괄 권한 요청 (현재) 모든 권한을 한 번에 요청 (사용자 이탈 높음) ``` **구현 방안:** - `/auth/gmail/login` - 기본 프로필 권한만 (간단한 로그인) - `/auth/gmail/connect-email` - Gmail 권한 추가 (이메일 아이템 사용 시) - DB에 권한 레벨 저장: `oauth_scopes` 필드 추가 - Frontend에서 권한 상태 표시 및 추가 연결 버튼 제공 ## 즉시 수정 필요 (Critical) ### 1. Frontend (robing-api.ts) ```typescript // 토큰 전송 추가 const token = localStorage.getItem('auth_token'); headers['Authorization'] = `Bearer ${token}`; ``` ### 2. Gateway (main.py) ```python # JWT 검증 추가 from app.core.auth import decode_access_token authorization = Header(None) if authorization: token = authorization.replace("Bearer ", "") payload = decode_access_token(token) username = payload.get("sub") # 또는 username ``` ### 3. Robing Service (storage.py) ```python # username 기반 컬렉션 생성 collection_name = f"{robing_id}_{username}_episodic" ``` ## 단계별 구현 계획 ### Phase 1: 긴급 패치 (1일) 1. Frontend에서 토큰 전송 2. Gateway에서 토큰 검증 3. username 기반 ChromaDB 분리 ### Phase 2: 표준화 (3일) 1. 변수명 통일 (username vs user_id) 2. JWT 페이로드 표준화 3. API 문서 작성 ### Phase 3: 개선 (1주) 1. 이메일-유저명 매핑 DB화 2. 토큰 갱신 로직 구현 3. 권한 체계 구현 ### Phase 4: OAuth 권한 분리 (1주) 1. 기본 로그인용 엔드포인트 구현 (최소 권한) 2. 스킬별 추가 권한 연결 엔드포인트 구현 3. DB에 사용자별 권한 상태 저장 4. Frontend에 권한 관리 UI 추가 ## 참고 사항 - **JWT Secret**: 모든 서비스가 같은 키 공유 필요 - **CORS 설정**: frontend URL 추가 필요 - **Redis**: 토큰 캐싱 및 세션 관리 활용 - **로그**: 모든 인증 실패 상세 로깅 ## 문서 작성자 - 작성일: 2025-08-16 - 작성자: 51123 서버 관리 Claude - 목적: 인증 시스템 통합을 위한 현황 분석