메인 콘텐츠로 건너뛰기
조회수 7

생성형 AI 도구를 활용하여 작성 및 편집된 노트입니다.

GCP에서 OAuth 인증 및 Google API(서비스) 사용 정리

OpenClaw 완전정복 : 설치부터 응용 사례까지

개념 구분: 프로젝트, API, OAuth 동의 화면, OAuth 클라이언트, 서비스 계정

GCP "프로젝트"는 결제, IAM, API 사용 설정이 묶이는 단위다. 어떤 Google API를 쓰든 보통 특정 프로젝트에서 API를 "활성화"해야 쿼터/과금/로그가 그 프로젝트에 잡힌다.1

image

image

image

"OAuth 동의 화면(OAuth consent screen)"은 사용자가 권한을 부여할 때 보게 되는 앱 정보(앱 이름, 로고, 개인정보처리방침 URL, 승인된 도메인, 요청 스코프, 테스트 사용자 등) 설정이다. 외부 사용자에게 배포하면 검증(verification)이 필요한 경우가 있다.2

"OAuth 클라이언트"는 OAuth 플로우에서 쓰는 클라이언트 식별자다(클라이언트 ID, 일부 유형은 클라이언트 시크릿 포함). 유형(웹, SPA, 데스크톱 등)에 따라 보안 가정과 리디렉션 URI 규칙이 다르다.3

"서비스 계정(Service Account)"은 사용자 계정이 아니라 서버/워크로드용 ID다. 서버-서버로 Google Cloud 리소스에 접근할 때 주로 쓰고, 사람 대신 동의 과정을 거치지 않는다. 권한은 IAM 역할로 부여한다.4

정리하면 "사용자 대신 접근"은 OAuth(동의+스코프) 중심이고, "서버가 자기 권한으로 접근"은 서비스 계정(IAM) 중심이다. 같은 API라도 접근 주체가 누구냐에 따라 인증 방식이 갈린다.

OAuth 2.0 주요 플로우 실무 요약

웹 서버(Authorization Code + PKCE)는 브라우저에서 로그인/동의를 진행하고, 서버가 authorization code를 받아 토큰으로 교환한다. 요즘은 웹 서버라도 PKCE를 같이 쓰는 게 기본에 가깝다(코드 탈취 완화).[^*] Google은 OAuth 클라이언트 유형에 맞게 리디렉션 URI를 엄격히 검사한다.3

SPA는 브라우저 내 자바스크립트 앱이다. 전통적인 "implicit" 대신 Authorization Code + PKCE를 권장하는 흐름이 일반적이다. 토큰을 브라우저 저장소에 장기 보관하는 설계는 사고가 나기 쉬워서, 세션/백엔드 중계(BFF) 같은 패턴을 함께 고민한다.

데스크톱 앱은 루프백(127.0.0.1) 리디렉션이나 커스텀 URI 스킴으로 돌아오는 방식을 쓴다. 설치형 앱이라 클라이언트 시크릿 보관이 취약하므로(노출 가능) "비밀이 없는 클라이언트"처럼 다루고 PKCE로 보완하는 쪽이 안전하다.

CLI/Device Code는 입력 장치가 제한된 환경(터미널, TV 등)에서 사용자에게 짧은 코드와 인증 URL을 안내하고, 사용자가 다른 기기/브라우저에서 승인하면 CLI가 토큰을 받는 방식이다. 자동화된 헤드리스 로그인보다는 사람이 승인하는 운영 도구에 잘 맞는다.5

콘솔 설정 절차(프로젝트 → API → 동의 화면 → 클라이언트 → 리디렉션 URI)

먼저 프로젝트를 만들고(또는 기존 프로젝트 선택) 해당 프로젝트에서 필요한 API를 활성화한다. 예를 들어 Sheets API를 쓰면 Google Sheets API를 켜야 한다.1

그다음 OAuth 동의 화면을 구성한다. 내부(Workspace 조직 내)인지 외부(일반 Google 계정 포함)인지에 따라 요구 사항이 달라지고, 외부 배포는 테스트 사용자/검증 이슈가 자주 생긴다.2

동의 화면이 준비되면 OAuth 클라이언트를 만든다. 앱 형태에 맞는 유형(웹 애플리케이션, 데스크톱 앱, 자바스크립트 등)을 고르고, 웹 유형이라면 승인된 리디렉션 URI를 정확히 등록한다. URI는 스킴/호스트/경로가 완전히 일치해야 하며, 오타나 http/https 차이로 실패가 많이 난다.3

마지막으로 앱에서 클라이언트 ID(필요 시 시크릿)와 리디렉션 URI를 설정하고, 요청할 스코프를 확정한다. 스코프는 최소로 시작하고, 정말 필요할 때만 추가하는 편이 운영이 쉽다.2

서비스 계정 사용(서버-서버), 키 관리, IAM 권한

서비스 계정은 "이 워크로드가 어떤 권한을 갖고 어떤 리소스에 접근할지"를 IAM으로 정의하는 방식이다. GCE/GKE/Cloud Run 같은 GCP 런타임에서는 가능하면 서비스 계정 키(JSON) 파일을 내려받아 배포하지 말고, 기본 자격 증명(Workload Identity 계열)을 써서 키 없는 방식으로 토큰을 발급받게 만드는 게 안전하다.46

부득이하게 키를 써야 한다면 키를 코드/이미지에 포함하지 말고 Secret Manager 같은 안전한 저장소에 넣고 주기적 회전(rotate)을 전제로 운영한다.7 또한 서비스 계정에 광범위한 권한(Owner 등)을 주는 대신 필요한 역할만 최소로 부여해야 한다.4

Google API 중 "사용자 데이터"가 핵심인 API(예: 개인 Google Drive/Sheets의 사용자 소유 문서)에 서비스 계정으로 접근하려면, 문서를 서비스 계정 이메일에 공유하거나(개인 계정 영역) 조직 환경에서는 도메인 위임(Workspace domain-wide delegation) 같은 추가 구성이 필요할 수 있다. 반면 GCS/BigQuery처럼 GCP 리소스는 보통 IAM만 맞으면 서비스 계정 접근이 자연스럽다.4

대표 사용 예: GCS/BigQuery/Sheets에서 OAuth vs 서비스 계정

GCS는 버킷/오브젝트가 GCP 리소스이므로 서비스 계정 + IAM이 정석이다. "사용자 개인 권한으로 내 GCS를 조작" 같은 UX가 필요하면 OAuth로 사용자 토큰을 받아서 접근할 수도 있지만, 대개 운영/배치/서버 백엔드는 서비스 계정이 단순하다.4

BigQuery도 프로젝트/데이터셋 단위 권한이 IAM으로 떨어지므로 서비스 계정이 일반적이다. 사용자가 콘솔에서 자기 권한으로 쿼리하고 그 결과를 앱에서 이어 받는 경험을 만들고 싶을 때는 OAuth로 사용자 동의를 받아 사용자 토큰으로 호출한다.4

Sheets API는 "사용자 소유의 스프레드시트"에 접근하는 경우가 많아서 OAuth가 자주 등장한다. 서비스 계정으로 하려면 대상 시트를 서비스 계정에 공유하거나(권한 부여) 조직 정책으로 위임을 구성해야 한다. 즉, 사용자 문서에 자연스럽게 접근하려면 OAuth, 서버가 관리하는 자동화 문서라면 서비스 계정(공유/소유 구조 포함)이 편하다.8

토큰, 스코프, 리프레시 토큰(오프라인 액세스), 만료/갱신

Access token은 API 호출 시 Authorization 헤더에 붙는 짧은 수명의 토큰이다. 스코프는 "이 토큰이 허용하는 권한 범위"이며, 스코프가 넓어질수록 사용자 동의 부담과 검증 요구가 커질 수 있다.28

Refresh token은(발급되는 플로우/클라이언트 조건에 따라) access token이 만료될 때 새 access token을 받는 데 쓴다. 사용자가 앱을 닫아도 계속 접근해야 하는 요구가 있으면 오프라인 액세스를 설계하고, refresh token은 사실상 장기 비밀로 취급해 서버 측 안전한 저장소에 보관한다.9

실무에서는 "401=토큰 만료/누락", "403=권한/스코프/IAM 부족"이 가장 흔하다. 우선 access token 재발급(리프레시 또는 재로그인)과 스코프/권한 매칭을 확인한다.94

예시: 토큰으로 Google API 호출(cURL 1개)

이미 발급받은 access token이 있다고 가정하면 호출은 보통 아래 형태다(예: Sheets API로 스프레드시트 메타데이터 조회).8

ACCESS_TOKEN="ya29...."
SPREADSHEET_ID="1abc..."

curl -sS \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  "https://sheets.googleapis.com/v4/spreadsheets/${SPREADSHEET_ID}"

예시: Authorization Code + PKCE 흐름(의사코드 1개)

앱이 해야 할 일만 남기면 아래 순서로 정리된다.39

# 1) 로그인 시작
code_verifier = random_string()
code_challenge = base64url(sha256(code_verifier))
redirect user to:
  https://accounts.google.com/o/oauth2/v2/auth?
    client_id=...
    response_type=code
    redirect_uri=https://app.example.com/oauth/callback
    scope=...
    code_challenge=code_challenge
    code_challenge_method=S256
    access_type=offline   # refresh token 필요 시
    prompt=consent        # 처음/재발급 필요 시

# 2) 콜백에서 code 수신
on GET /oauth/callback?code=...

# 3) 서버가 토큰 교환
POST https://oauth2.googleapis.com/token with:
  grant_type=authorization_code
  code=...
  client_id=...
  (client_secret=... if applicable)
  redirect_uri=...
  code_verifier=code_verifier

# 4) 응답의 access_token으로 API 호출, refresh_token은 안전 저장

보안/운영 팁: 실무에서 자주 막히는 지점

클라이언트 시크릿, 서비스 계정 키 같은 민감정보는 코드/환경변수에 무심코 퍼지기 쉽다. Secret Manager를 기준으로 "저장(Secret)-접근(IAM)-회전(운영)"을 한 세트로 잡아두면 사고가 줄어든다.7

권한은 최소권한이 기본이다. 서비스 계정에는 필요한 IAM 역할만 주고, OAuth 스코프도 필요한 범위만 요청한다. OAuth 동의 화면에서 승인 도메인/개인정보처리방침/테스트 사용자 설정이 불완전하면 외부 사용자 테스트가 막히거나 검증 단계에서 지연이 난다.2

리디렉션 URI 불일치는 매우 흔한 장애 원인이다. 콘솔 등록 값과 실제 콜백 URL이 스킴/포트/경로까지 완전히 같은지 먼저 본다.3

401/403이 나면 "어떤 주체로 호출 중인지"부터 분리해서 본다. OAuth라면 토큰 만료/스코프 부족/잘못된 대상 계정 문제를, 서비스 계정이라면 IAM 역할 부여 위치(프로젝트/버킷/데이터셋)와 조직 정책 제한을 의심한다.49

빠른 체크리스트와 자주 하는 실수

프로젝트가 맞는지, 필요한 API가 켜져 있는지부터 확인한다.1

OAuth 동의 화면에서 앱 정보, 승인 도메인, 테스트 사용자, 요청 스코프가 실제 배포 형태와 일치하는지 점검한다.2

OAuth 클라이언트 유형이 앱 형태와 맞는지(웹/SPA/데스크톱), 리디렉션 URI가 완전 일치하는지 확인한다.3

오프라인 액세스가 필요한데 refresh token이 안 나오는 경우는 보통 프롬프트/클라이언트 조건/동의 이력에 걸린다. refresh token을 "클라이언트에 저장"하는 실수도 잦으니 서버 저장을 원칙으로 둔다.9

서비스 계정 키 파일을 깃에 올리거나 이미지에 포함하는 실수를 피한다. 가능하면 키 없는 방식(런타임 기본 자격 증명)으로 설계하고, 꼭 필요하면 Secret Manager+회전으로 운영한다.67

Sheets처럼 사용자 문서가 대상인데 서비스 계정으로 바로 되길 기대하는 경우가 많다. 공유(서비스 계정 이메일 추가) 또는 조직 위임 같은 전제가 필요하다는 점을 먼저 확인한다.8

참고

1Google Cloud API 사용(활성화/관리) 문서

2OAuth 동의 화면 구성(External/Internal, 검증 관련)

3Google OAuth 2.0 엔드포인트 및 클라이언트 유형 개요

4서비스 계정 개요 및 IAM 권한 부여

5OAuth 2.0 for TV and Limited-Input Device Applications(Device Code)

6애플리케이션 기본 사용자 인증 정보(Application Default Credentials)

7Secret Manager 개요

8Google Sheets API 개요

9OAuth 2.0: 액세스/리프레시 토큰 동작

이 노트는 요약·비평·학습 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.