Troubleshooting 2026.08.11 5 min read

Google OAuth 테스트 모드의 7일 refresh token 함정

rclone 인증 후 OAuth 앱의 Testing 상태를 확인했다. 7일 만료 조건과 다른 client에 미치는 영향을 나눠 보고 새 token으로 백업을 검증했다.

이슈 발생: 2026-08-09 · 발행 기준: 2026-08-10 11:52 KST
환경: Google OAuth, rclone, Kubernetes 정기 백업, Cloudflare Access

rclone용 Google OAuth client를 만들고 인증을 마친 뒤 동의 화면 상태를 확인했다. External / Testing 상태에서는 특정 scope로 발급받은 refresh token이 7일 뒤 만료될 수 있었다. 이 상태로 두면 정기 백업이 멈추고 다시 브라우저 인증을 해야 할 수 있었다.

변경 전에 두 가지를 확인했다.

  1. OAuth 앱을 Production으로 바꾸면 7일 제한이 없어지는가?
  2. 같은 Google Cloud 프로젝트에서 사용 중인 다른 OAuth client의 ID나 secret도 바뀌는가?

확인한 범위에서는 동의 화면을 Production으로 바꿔도 기존 OAuth client의 ID, secret, 승인된 JavaScript origin과 redirect URI는 자동으로 바뀌지 않는다. Testing 상태에서 받은 token이 그대로 장기 token이 된다고 가정하지는 않았다. 게시 후 rclone을 다시 승인해 새 refresh token을 받았다.

OAuth에서 구분해야 할 세 층

Google Cloud 프로젝트
  ├─ OAuth 동의 화면: Internal/External, Testing/Production
  ├─ OAuth client A: rclone Desktop client
  └─ OAuth client B: Cloudflare Access용 Web client

동의 화면의 게시 상태는 프로젝트 차원의 설정이다. 반면 client ID, client secret, origin, redirect URI는 개별 OAuth client의 설정이다.

그래서 같은 프로젝트의 다른 client가 어디에 쓰이는지 먼저 확인했다. 게시 상태를 바꾸는 작업과 각 client의 자격 증명을 회전하는 작업은 구분했다.

Testing 상태에서 왜 7일인가

Google OAuth 문서에서 외부 사용자 유형의 Testing 앱이 특정 scope를 요청하면 refresh token이 7일 뒤 만료될 수 있다는 조건을 확인했다. 로그인 직후의 성공만으로는 장기 자동화에 사용할 수 있는지 판단할 수 없었다.

자동 백업에서 access token은 짧게 사용되고, 만료되면 refresh token으로 새 access token을 받는다. refresh token 자체가 사라지면 사람의 브라우저 재인증 없이는 다음 백업이 계속 실패한다.

access token 만료
  → refresh token으로 재발급
  → refresh token도 만료됨
  → interaction_required / invalid_grant
  → 자동 백업 중단

Production 전환 전 점검

같은 프로젝트에서 Cloudflare Access용 Google 로그인을 사용하고 있었기 때문에 다음 항목을 먼저 기록했다.

  • OAuth client 목록과 각 client 유형(Desktop/Web)
  • Web client의 승인된 JavaScript origin
  • Web client의 승인된 redirect URI
  • Cloudflare Access의 Google IdP 설정
  • rclone이 사용할 Desktop client
  • OAuth 동의 화면의 scope와 test user

비교할 때는 이름, 유형, URI 존재 여부만 확인했다. client secret과 token은 출력하거나 화면 캡처에 남기지 않았다.

안전하게 전환한 순서

  1. rclone 전용 Desktop OAuth client를 별도로 만든다.
  2. Google Drive API가 활성화되어 있는지 확인한다.
  3. OAuth 동의 화면을 External / Production으로 게시한다.
  4. 기존 Web client의 ID, redirect URI가 그대로인지 확인한다.
  5. Cloudflare Access 로그인을 실제로 시험한다.
  6. rclone을 다시 승인해 새 refresh token을 발급한다.
  7. Kubernetes Secret을 새 설정으로 교체한다.
  8. 수동 백업과 정기 백업을 각각 검증한다.

5번에서 기존 서비스의 로그인을 확인한 뒤 6번의 백업용 token 갱신을 진행했다. 프로젝트 공용 설정을 바꾼 영향과 백업 자격 증명을 교체한 영향을 나눠 보기 위해서였다.

Kubernetes 반영 시 주의점

rclone 설정 파일에는 client secret과 token JSON이 들어간다. 임시 파일의 권한과 명령 기록을 점검해야 한다.

# Secret 값을 보지 않고 메타데이터만 확인
kubectl -n backup get secret <rclone-secret> \
  -o custom-columns=NAME:.metadata.name,UPDATED:.metadata.creationTimestamp

# 교체 후 새 Job으로 검증
kubectl -n backup create job \
  --from=cronjob/<backup-cronjob> <oauth-validation-job>

Secret 갱신 후에는 새 Job으로 확인했다. 환경변수로 받은 값은 새 Pod에서 읽어야 하고, volume으로 받은 값도 애플리케이션이 다시 읽는지 확인해야 한다. 기존 Pod의 성공 여부만으로 교체 결과를 판단하지 않았다.

검증 결과를 판단하는 기준

  • Cloudflare Access의 기존 Google 로그인이 그대로 성공한다.
  • 기존 Web client의 ID/secret/redirect URI가 변경되지 않았다.
  • rclone이 새 token으로 Drive 목록 조회 및 업로드에 성공한다.
  • 백업 Job 로그에 invalid_grant, interaction_required가 없다.
  • 다음 정기 실행에서도 브라우저 개입 없이 성공한다.
  • 복원 시험까지 통과한다.

오해하기 쉬운 부분

Production이면 Google 검증이 항상 필요한가?

앱이 요청하는 scope와 사용자 범위에 따라 검증 요구가 달라진다. Production 전환과 Google의 앱 검증 완료는 같은 말이 아니다. 콘솔에 표시되는 경고와 사용자 제한을 실제 scope 기준으로 확인해야 한다.

게시하면 기존 key가 바뀌는가?

아니다. 게시 상태 변경은 자동 key rotation이 아니다. client secret을 직접 재설정하거나 client를 삭제하지 않는 한 별개의 작업이다.

Testing 때 받은 token을 계속 써도 되는가?

이번 백업에서는 계속 사용하지 않았다. 게시 후 새로 승인한 token을 실제 Job에 넣어 확인했다.

재발 방지

  • OAuth client마다 용도를 이름에 표시한다.
  • 다른 서비스가 함께 쓰는 프로젝트라면 영향도 표를 먼저 만든다.
  • invalid_grant와 연속 백업 실패에 알림을 둔다.
  • token 교체 절차와 복구 절차를 함께 문서화한다.
  • 비밀값을 화면·로그·Git에 남기지 않는다.

참고 자료

SEARCH JOURNAL

기록 검색

글 제목, 요약, 태그에서 찾습니다.

검색을 준비하고 있어요.

검색어를 입력해 주세요.

    Ctrl/⌘ K 검색 Esc 닫기 ↑ ↓ 결과 이동