# Email Skill 인증 오류 및 Cron 토큰 문제 **작성일**: 2025-09-13 **작성자**: happybell80 & Claude **영향 서비스**: skill-email, rb8001 **심각도**: 높음 ## 1. 문제 상황 ### Email Skill HTTP 500 오류 - **증상**: skill_email 서비스가 HTTP 500 반환 - **에러**: `No credentials found for user: 0914eagle@gmail.com` - **영향**: 3명 사용자 이메일 동기화 실패 - 0914eagle (0914eagle@gmail.com) - 토큰 있음, 만료 - happybell80 (goeun2dc@gmail.com) - 토큰 있음, 만료 - cdctfm (cdctfm@gmail.com) - 토큰 없음 ### Cron 트리거 권한 오류 - **증상**: `Unauthorized cron trigger attempt` 경고 발생 - **위치**: rb8001/main.py:558 - **문제**: 인증 실패에도 요청 처리 계속됨 (보안 취약) ## 2. 원인 분석 ### Email 인증 실패 원인 ```python # skill-email/services/gmail_service.py:49 if creds_result is None: return Err(EmailError(f"No credentials found for user: {user_id}")) # skill-email/services/db_credentials_provider.py:67 SELECT token_data->>'refresh_token' as refresh_token FROM gmail_token # 테이블명 맞음: 실제 DB도 gmail_token (단수형) WHERE slack_user_id = %s AND is_equipped = true ``` 1. **테이블명 일치**: 코드와 DB 모두 `gmail_token` 단수형 2. **토큰 현황**: 2명 refresh_token 보유 (0914eagle, happybell80), 1명 없음 (cdctfm) 3. **만료 상태**: 3명 전원 access_token 만료 (08-18~08-23 생성) ### Cron 인증 취약점 ```python # rb8001/main.py:556-560 expected_token = settings.CRON_TOKEN if hasattr(settings, 'CRON_TOKEN') else "cron-secret-2024" if auth_header != f"Bearer {expected_token}": logger.warning("Unauthorized cron trigger attempt") # raise HTTPException(status_code=401, detail="Unauthorized") # 주석 처리됨! ``` - 하드코딩된 기본 토큰 사용 - 인증 실패시 경고만 기록, 요청은 계속 처리 ## 3. 관련 문서 참조 - **250909**: gmail_refresh_token 컬럼/JSONB 불일치 해결 - **250825**: Gmail 토큰 만료 문제 (동일 사용자 3명) - **250801**: 크론잡 로그 동기화 설정 ## 4. 해결 방안 ### 즉시 조치 (로컬 개발자) ```python # 1. refresh_token으로 access_token 자동 갱신 구현 필요 # skill-email/services/gmail_service.py:62-66 if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) # 이미 구현되어 있음 # 2. Cron 문제는 해결됨 (엔드포인트 삭제 완료) ``` ### 서버 작업 필요 (서버 관리자) ```sql -- 현재 상태: 0914eagle, happybell80는 refresh_token 있음 -- cdctfm은 토큰 없어 재인증 필요 -- is_equipped 설정 (토큰 있는 사용자만) UPDATE gmail_token SET is_equipped = true WHERE slack_user_id IN ('0914eagle', 'happybell80'); -- cdctfm은 Gmail 재인증 필요 ``` ## 5. 교훈 1. **DB 현황**: gmail_token 테이블 3건 (2명 토큰 보유, 1명 없음) 2. **토큰 상태**: 전원 access_token 만료, refresh_token 자동 갱신 필요 3. **auth-server**: gmail_tokens와 gmail_token 혼용 중 4. **해결 방법**: is_equipped=true 설정 + refresh 로직 활용