DOCS/journey/troubleshooting/250821_gmail_token_auto_refresh.md
Claude-51124 22557e7132 docs: 오래된 트러블슈팅 아카이브 및 구조 정리
- 7-8월 초기 구축 문서 12개를 _archive/troubleshooting/2025_07-08_initial_setup/로 이동
- book/300_architecture/390_human_in_the_loop_intent_learning.md를 journey/research/intent_classification/로 이동 (개발 여정 문서)
- 빈 폴더 제거 (journey/assets/*)
2025-11-17 14:06:05 +09:00

5.8 KiB

Gmail 토큰 자동 갱신 기능 구현

작성일: 2025-08-21

작성자: Claude (with heejae)


1. 개요

Gmail OAuth 토큰의 자동 갱신 기능을 auth-server에 구현하여, 만료된 access_token을 refresh_token을 사용해 자동으로 갱신할 수 있도록 함.

1.1 배경

  • Gmail access_token은 1시간 후 만료
  • refresh_token을 사용하여 새 access_token 발급 필요
  • skill-email 서비스가 토큰 만료로 이메일 발송 실패하는 문제 해결 필요

2. 데이터베이스 구조

2.1 현재 DB 정보

Database: main_db (auth_db 아님 주의!)
Table: gmail_token

2.2 gmail_token 테이블 구조

CREATE TABLE gmail_token (
    id SERIAL PRIMARY KEY,
    user_id UUID UNIQUE NOT NULL,
    robeing_id VARCHAR(50),
    token_data JSONB NOT NULL,      -- access_token, refresh_token, token_type
    oauth_config JSONB,              -- client_id, client_secret, token_uri
    scopes JSONB,                    -- Gmail API 권한 목록
    metadata JSONB,                  -- email, source_file 등
    expiry TIMESTAMP,                -- 토큰 만료 시간
    is_equipped BOOLEAN DEFAULT false,
    equipped_to VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

2.3 현재 저장된 토큰

User ID Email 상태
b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0 0914eagle@gmail.com refresh_token 무효
dddddddd-dddd-dddd-dddd-dddddddddddd test@gmail.com 정상 작동

3. auth-server 자동 갱신 API

3.1 구현 파일

  • /home/heejae/auth-server/app/api/gmail_refresh.py

3.2 엔드포인트

3.2.1 토큰 상태 확인

GET /api/gmail/check/{user_id}

응답 예시:

{
    "status": "found",
    "user_id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
    "email": "test@gmail.com",
    "has_token": true,
    "has_access_token": true,
    "has_refresh_token": true,
    "has_oauth_config": true,
    "is_expired": false,
    "remaining_seconds": 34620,
    "needs_refresh": false
}

3.2.2 토큰 자동 갱신

POST /api/gmail/refresh/{user_id}

응답 예시 (유효한 토큰):

{
    "status": "valid",
    "user_id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
    "email": "test@gmail.com",
    "expires_in": 34550,
    "access_token": "ya29.a0AS3H6Nxc8Z61FzHnEYmJ9TckEa0Yj8zd9Y6..."
}

응답 예시 (갱신된 토큰):

{
    "status": "refreshed",
    "user_id": "dddddddd-dddd-dddd-dddd-dddddddddddd",
    "email": "test@gmail.com",
    "expires_in": 3600,
    "access_token": "ya29.a0AS3H6NxNEW_TOKEN_HERE..."
}

3.3 갱신 로직

  1. 토큰 만료 확인 (5분 이상 남았으면 갱신 안함)
  2. refresh_token으로 Google OAuth API 호출
  3. 새 access_token 받아서 DB 업데이트
  4. 만료 시간(expiry) 업데이트

4. 문제 해결 과정

4.1 데이터베이스 문제

  • 문제: auth_db가 존재하지 않음
  • 해결: main_db 사용으로 변경

4.2 Docker 네트워크 문제

  • 문제: Docker 컨테이너에서 localhost 접근 불가
  • 해결: host.docker.internal 사용

4.3 refresh_token 무효 문제

  • 원인:
    • Google OAuth 앱이 테스트 모드
    • 6개월 이상 미사용 시 자동 만료
    • 사용자가 권한 취소
  • 해결: 재인증 필요

5. 테스트 방법

5.1 토큰 상태 확인

curl -X GET "http://localhost:9000/api/gmail/check/{user_id}"

5.2 토큰 갱신

curl -X POST "http://localhost:9000/api/gmail/refresh/{user_id}"

5.3 로컬 테스트 스크립트

python3 /home/heejae/test_refresh.py

6. Gmail 재인증 방법

6.1 OAuth 재인증 URL

http://localhost:9000/auth/gmail/passport?user_id={user_id}

6.2 "액세스 차단됨" 에러 해결

  1. Google Cloud Console 접속
  2. APIs & Services → OAuth consent screen
  3. Test users에 이메일 추가
  4. 또는 기존 권한 삭제 후 재시도

6.3 주의사항

  • gmail/login (로그인용) vs gmail/passport (API 권한용) 구분
  • passport 엔드포인트 사용해야 gmail.send 권한 획득

7. 환경 설정

7.1 auth-server 환경변수 (.env)

DATABASE_URL=postgresql://robeings:robeings@host.docker.internal:5432/main_db
GOOGLE_CLIENT_ID=1044056803209-0h8n5kcl22rvl740mdgpejp58v27mlro.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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

7.2 Docker 실행

cd /home/heejae/auth-server
docker compose down && docker compose up -d --build

8. 다음 단계

8.1 완료된 작업

  • auth-server에 자동 갱신 API 구현
  • test@gmail.com 계정 테스트 완료
  • DB 연결 및 구조 확인

8.2 TODO

  • 0914eagle@gmail.com 토큰 갱신 완료 (2025-08-27 10:34 - 리프레시 토큰으로 자동 갱신)
  • skill-email 자체 갱신 구현 완료 (2025-08-27 - Google 라이브러리 직접 사용)
  • gmail_passport.py를 현재 DB 구조(JSONB)에 맞게 수정
  • 토큰 만료 알림 기능 추가 고려

9. 참고사항

9.1 refresh_token 수명

  • 프로덕션 앱: 6개월 미사용 시 만료
  • 테스트 앱: 7일 후 만료
  • 해결: 정기적 갱신 또는 프로덕션 모드 전환

9.2 민감한 스코프

  • gmail.send, gmail.modify는 제한된 스코프
  • Google 검증 필요할 수 있음

9.3 UUID 변경 이력

  • 원래: heejae, test, unknown (VARCHAR)
  • 현재: UUID 형식으로 변경
  • heejae → b6ea2ee0-a15a-5cf4-93a9-a9ca20d4c4a0

10. 관련 문서

  • /home/heejae/DOCS/250818_gmail_token_database_setup.md
  • /home/heejae/DOCS/robeing-monitor-integration.md
  • /home/heejae/DOCS/250817_slack_user_mapping_troubleshooting.md