# 로빙 프로젝트 인증 시스템 전체 분석 및 통합 방안 ## 현재 구조 분석 ### 1. 데이터베이스 (PostgreSQL - main_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 - robeing_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_EXPIRATION_DAYS: 30 (일) # 코드에서 사용 - JWT_ACCESS_TOKEN_EXPIRE_MINUTES: 30 (분) # .env에만 존재, 미사용 #### 이메일-유저명 매핑 (하드코딩) ```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 // robeing-api.ts - 토큰 전송 안함! export async function sendMessage(text: string, userId: string = 'test_user') { // Authorization 헤더 없음 // 모든 사용자가 'test_user'로 처리됨 } ``` ### 4. Robeing Gateway (포트 8100) #### 현재 처리 방식 ```python # main.py:92-95 x_user_id: Optional[str] = Header(None) # X-User-Id 헤더만 확인 # JWT 토큰 검증 없음! ``` ### 5. Robeing Services (51124 서버) #### ChromaDB 컬렉션명 생성 ```python # rb10508_micro/app/core/memory/storage.py collection_name = f"{settings.ROBEING_ID}_{username if username else 'default'}_{memory_type}" # 현재: rb10508_micro_default_episodic (모든 사용자 공유!) # 문제: endpoints.py에서 username 전달하지 않음 # endpoints.py:22 - 기본값: "default_user" ``` #### 서비스 포트 - rb8001: 포트 8001 - rb10508_micro: 포트 10508 - rb10408_test: 포트 10408 #### 환경변수 현황 - AUTH_SERVER_URL: `http://192.168.0.100:9000` (설정됨) - JWT_SECRET_KEY: `your-jwt-secret-key` (기본값, 변경 필요) ## 주요 문제점 ### 1. ~~인증 토큰 미전송~~ ✅ 해결됨 - ~~Frontend가 API 호출 시 JWT 토큰을 전송하지 않음~~ - ~~`robeing-api.ts`에 Authorization 헤더 없음~~ - **수정 완료**: robeing-api.ts:40, chat-interface.tsx:275-279에서 토큰 전송 구현 ### 2. 백엔드 토큰 미검증 ⚠️ - Robeing Gateway가 JWT 토큰을 검증하지 않음 - X-User-Id 헤더만 확인 (누구나 위조 가능) ### 3. 사용자 식별 실패 및 채널별 메모리 분리 ⚠️ - endpoints.py에서 username 파라미터를 storage.py로 전달하지 않음 - user_id는 받지만 username으로 변환하지 않음 - **채널별 다른 컬렉션 사용 문제**: - Slack: `rb10508_micro_happybell80_episodic` (Auth 서버 매핑 제공) - Frontend: `rb10508_micro_default_episodic` (모든 사용자 공유) - **동일 사용자(happybell80)가 두 채널에서 다른 메모리 공간 사용** - 대화 내용 분리로 연속성 상실 ### 4. 이메일-유저명 매핑 하드코딩 📝 - 새 사용자 추가 시 코드 수정 필요 - 확장성 없음 ### 5. OAuth 권한 과다 요청 🔐 - 회원가입/로그인 시 Gmail 읽기/쓰기 권한(`gmail.modify`)까지 요청 - 복잡한 동의 과정으로 사용자 이탈 가능성 높음 - 이메일 기능 미사용자에게도 과도한 권한 요청 ### 6. 변수명 불일치 혼란 🔄 - user_id vs username vs email 혼용 - JWT의 'sub'에 username 저장 중 (gmail.py:184) - endpoints.py는 user_id 사용, storage.py는 username 필요 ### 7. Slack 통합과 인증 체계 불일치 🔗 - **Slack OAuth와 Google OAuth 별개 운영** - Slack 워크스페이스 인증 (봇 토큰) - Google 개인 인증 (사용자 토큰) - 두 시스템 간 연결 고리 불명확 - **Slack 사용자 매핑 문제** - slack_user_id (U0925SXQFDK) ↔ user_id (UUID) 매핑 필요 - 현재 하드코딩된 매핑 3개만 존재 - 신규 Slack 사용자 자동 연결 방법 없음 - **복잡한 관계 구조** ``` Slack Workspace ← SlackWorkspaces 테이블 ↓ Slack User ID ← slack_user_mapping 테이블 ↓ User (UUID) ← users 테이블 ↓ Google Account (OAuth) ``` - **권한 충돌 가능성** - Slack 봇 권한: chat:write, channels:read 등 - Google 권한: gmail.modify, calendar.events 등 - 같은 사용자가 두 가지 인증 경로 보유 ### 8. JWT Secret 불일치 🔑 - Auth Server: `ro-being-auth-jwt-secret-key-2024` - Robeing Services: `your-jwt-secret-key` (기본값) - 토큰 검증 시 실패할 수 있음 ## 결정 필요 사항 ### 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: {robeing_id}_{username}_episodic 예: rb10508_happybell80_episodic 옵션 B: {robeing_id}_{user_uuid}_episodic 예: rb10508_a1b2c3d4_episodic 옵션 C: {workspace_id}_{robeing_id}_{username}_episodic 예: workspace1_rb10508_happybell80_episodic ``` ### 5. 토큰 저장 키 통일 ```javascript 현재: 'auth_token' 대안: 'jwt_token', 'access_token', 'robeing_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에서 권한 상태 표시 및 추가 연결 버튼 제공 ### 7. Slack과 Google 인증 통합 전략 ``` 옵션 A: 통합 인증 (하나의 주 계정) - Google 로그인을 주 인증으로 사용 - Slack은 추가 연결 (선택적) - 장점: 단순한 인증 흐름 - 단점: Slack 전용 사용자 지원 어려움 옵션 B: 독립 인증 (현재) - Google과 Slack 각각 독립 인증 - 수동 매핑 필요 - 장점: 유연성 - 단점: 복잡한 관리 옵션 C: 자동 연결 (추천) ✅ - 이메일 기반 자동 매칭 - Slack 이메일 == Google 이메일 시 자동 연결 - 불일치 시 수동 연결 옵션 제공 ``` **구현 방안:** - Slack 사용자가 처음 메시지 전송 시: 1. Slack API로 이메일 조회 2. users 테이블에서 같은 이메일 검색 3. 매칭되면 자동으로 slack_user_mapping 생성 4. 없으면 임시 계정 생성 후 연결 대기 ## 즉시 수정 필요 (Critical) ### 통합 해결 방안 (우선순위별) #### 1. Auth 서버 JWT 활용 (권장) 🌟 ``` Frontend 로그인 → JWT(username 포함) → Gateway 검증 → Robeing username 추출 → Slack과 동일한 컬렉션 사용 (rb10508_micro_happybell80_episodic) ``` #### 2. Frontend user_id 전달 개선 ``` 로그인 후 username을 user_id로 전송 현재: user_id = "default_user" 개선: user_id = "happybell80" ``` #### 3. 통합 매핑 테이블 구축 ``` Auth 서버에 통합 매핑: email ↔ slack_id ↔ username - Frontend: email → username - Slack: slack_id → username - 결과: 동일 username으로 통합 메모리 ``` **관련 문서**: [Auth DB 테이블 구조 단순화 방안](/plans/250812_main_db_테이블_단순화_방안.md) ##### 현재 테이블 구조 (5개) - **users**: 사용자 기본 정보 (email, username) - **workspaces**: 워크스페이스 정보 (로빙 할당) - **workspace_member**: 사용자-워크스페이스 연결 - **slack_workspaces**: Slack 워크스페이스 정보 - **slack_user_mapping**: Slack ID ↔ User ID 매핑 (3개만 존재) ##### 제안된 통합 구조 (4개 테이블로 단순화) ```sql -- 1. users: 기존 유지 -- 2. slack_workspaces: 단순화 -- 3. user_robeings: 사용자-로빙 직접 연결 CREATE TABLE user_robeings ( user_id UUID REFERENCES user(id), robeing_id VARCHAR(100), -- rb10508_micro 등 is_primary BOOLEAN ); -- 4. slack_users: 통합 매핑 테이블 (핵심!) CREATE TABLE slack_users ( slack_user_id VARCHAR(100), -- U0925SXQFDK slack_team_id VARCHAR(100), user_id UUID REFERENCES user(id), robeing_id VARCHAR(100) -- Slack별 로빙 지정 가능 ); ``` ### 개별 수정 사항 #### 1. ~~Frontend (robeing-api.ts)~~ ✅ 완료 ```typescript // 수정 완료 - robeing-api.ts:38-41 if (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. Robeing Service (rb10508_micro) ```python # endpoints.py 수정 필요: # 1. JWT 토큰에서 username 추출 # 2. storage 함수 호출 시 username 전달 # storage.py는 이미 준비됨: collection_name = f"{settings.ROBEING_ID}_{username if username else 'default'}_{memory_type}" ``` ## 단계별 구현 계획 ### Phase 1: 긴급 패치 1. ~~Frontend에서 토큰 전송~~ ✅ 완료 2. Gateway에서 토큰 검증 3. username 기반 ChromaDB 분리 ### Phase 2: 표준화 1. 변수명 통일 (username vs user_id) 2. JWT 페이로드 표준화 3. API 문서 작성 ### Phase 3: 개선 1. 이메일-유저명 매핑 DB화 2. 토큰 갱신 로직 구현 3. 권한 체계 구현 ### Phase 4: OAuth 권한 분리 1. 기본 로그인용 엔드포인트 구현 (최소 권한) 2. 스킬별 추가 권한 연결 엔드포인트 구현 3. DB에 사용자별 권한 상태 저장 4. Frontend에 권한 관리 UI 추가 ### Phase 5: Slack-Google 인증 통합 1. 이메일 기반 자동 매칭 로직 구현 2. Slack 사용자 첫 메시지 시 자동 계정 생성 3. 수동 연결 UI 개발 4. 통합 대시보드 구현 ## 참고 사항 - **JWT Secret**: 모든 서비스가 같은 키 공유 필요 - **CORS 설정**: frontend URL 추가 필요 - **Redis**: 토큰 캐싱 및 세션 관리 활용 - **로그**: 모든 인증 실패 상세 로깅 ## 문서 작성자 - 작성일: 2025-08-16 - 작성자: 51123 서버 관리 Claude - 목적: 인증 시스템 통합을 위한 현황 분석