DOCS/troubleshooting/250913_happybell80_email_skill_auth_cron_errors.md
happybell80 d82404229b docs: Email Skill 인증 오류 및 Cron 토큰 문제 트러블슈팅
- Email Skill HTTP 500 오류 분석 (3명 사용자 영향)
- gmail_token vs gmail_tokens 테이블명 불일치 문제 파악
- Cron 인증 취약점 확인 (401 에러 주석 처리됨)
- 해결방안 제시: 테이블명 수정, Cron 인증 강화

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 11:32:57 +09:00

3.1 KiB

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명 사용자 이메일 동기화 실패 (매분 재시도 중)

Cron 트리거 권한 오류

  • 증상: Unauthorized cron trigger attempt 경고 발생
  • 위치: rb8001/main.py:558
  • 문제: 인증 실패에도 요청 처리 계속됨 (보안 취약)

2. 원인 분석

Email 인증 실패 원인

# 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:63
SELECT token_data->>'refresh_token' as refresh_token
FROM gmail_token  # 테이블명 문제: 실제 DB는 gmail_tokens (복수형)
WHERE slack_user_id = %s AND is_equipped = true
  1. 테이블명 불일치: 코드는 gmail_token, DB는 gmail_tokens
  2. 토큰 데이터 구조: token_data JSONB 내부에 저장 (250909 문서 확인)
  3. is_equipped 조건: 토큰이 있어도 장착되지 않으면 조회 실패

Cron 인증 취약점

# 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. 해결 방안

즉시 조치 (로컬 개발자)

# 1. skill-email 테이블명 수정
# services/db_credentials_provider.py:67
- FROM gmail_token
+ FROM gmail_tokens  # 복수형으로 수정

# 2. Cron 인증 강화
# rb8001/main.py:560
- # raise HTTPException(status_code=401, detail="Unauthorized")
+ raise HTTPException(status_code=401, detail="Unauthorized")

서버 작업 필요 (서버 관리자)

-- 토큰 상태 확인
SELECT slack_user_id, is_equipped, 
       token_data->>'refresh_token' IS NOT NULL as has_token
FROM gmail_tokens 
WHERE slack_user_id IN ('0914eagle', 'happybell80', 'cdctfm');

-- is_equipped 설정
UPDATE gmail_tokens 
SET is_equipped = true 
WHERE slack_user_id IN ('0914eagle', 'happybell80', 'cdctfm');

5. 교훈

  1. 테이블명 일관성: 단수/복수형 통일 필요 (250911 문서 참조)
  2. 보안 우선: 인증 실패시 반드시 요청 차단
  3. 환경변수 사용: 하드코딩 대신 .env 파일 활용
  4. 토큰 관리: JSONB 구조로 일원화 완료, 테이블명만 수정 필요