서버 간 애플리케이션에 OAuth 2.0 사용

자세한 내용은 Google Cloud Platform 문서의 인증 개요를 참조하세요.

Google OAuth 2.0 시스템은 웹 애플리케이션과 Google 서비스 간 상호작용과 같은 서버 간 상호작용을 지원합니다. 이 상황에서는 개별 최종 사용자가 아닌 애플리케이션에 속한 계정인 서비스 계정이 필요합니다. 애플리케이션은 서비스 계정을 대신하여 Google API를 호출하므로 사용자는 직접 관여하지 않습니다. 이 시나리오에서는 "2-legged OAuth (관련 용어 'Three-legged OAuth&quot'는 애플리케이션이 최종 사용자를 대신하여 Google API를 호출하며 경우에 따라 사용자 동의가 필요한 시나리오를 의미합니다.)

일반적으로 애플리케이션이 Google 계정을 사용하여 사용자 데이터가 아닌 자체 데이터를 작업하는 경우 서비스 계정을 사용합니다. 예를 들어 데이터 지속성을 위해 Google Cloud Datastore를 사용하는 애플리케이션은 서비스 계정을 사용하여 Google Cloud Datastore API 호출을 인증합니다.

또한 Google Workspace 도메인 관리자는 서비스 계정에 도메인 전체 권한을 부여하여 도메인의 사용자를 대신하여 사용자 데이터에 액세스할 수도 있습니다.

이 문서에서는 애플리케이션이 Google API 클라이언트 라이브러리 (권장) 또는 HTTP를 사용하여 서버 간 OAuth 2.0 흐름을 완료하는 방법을 설명합니다.

개요

서버 간 상호작용을 지원하려면 먼저 에서 프로젝트의 서비스 계정을 만듭니다. Google Workspace 계정 사용자의 사용자 데이터에 액세스하려면 서비스 계정에 도메인 차원 액세스 권한을 위임하세요.

그러면 애플리케이션에서 서비스 계정의 사용자 인증 정보를 사용하여 OAuth 2.0 인증 서버에 액세스 토큰을 요청하여 승인된 API를 호출할 준비를 합니다.

마지막으로 애플리케이션은 액세스 토큰을 사용하여 Google API를 호출할 수 있습니다.

서비스 계정 만드는 중

서비스 계정의 사용자 인증 정보에는 고유하고 하나 이상의 공개/비공개 키 쌍이 생성된 이메일 주소가 포함됩니다. 도메인 전체 위임을 사용 설정하면 클라이언트 ID도 서비스 계정의 사용자 인증 정보에 포함됩니다.

애플리케이션이 Google App Engine에서 실행되는 경우 프로젝트를 만들 때 서비스 계정이 자동으로 설정됩니다.

애플리케이션이 Google Compute Engine에서 실행되는 경우 프로젝트를 만들 때 서비스 계정이 자동으로 설정되지만 Google Compute Engine 인스턴스를 만들 때 애플리케이션에서 액세스해야 하는 범위를 지정해야 합니다. 자세한 내용은 서비스 계정을 사용하도록 인스턴스 준비를 참조하세요.

애플리케이션이 Google App Engine 또는 Google Compute Engine에서 실행되지 않는 경우 에서 사용자 인증 정보를 가져와야 합니다. 서비스 계정 사용자 인증 정보를 생성하거나 이미 생성한 공개 사용자 인증 정보를 보려면 다음 단계를 따르세요.

먼저 서비스 계정을 만듭니다.

  1. 오픈 Service accounts page.
  2. If prompted, select a project, or create a new one.
  3. 클릭 서비스 계정을 만듭니다.
  4. 서비스 계정 정보에서 서비스 계정의 이름, ID 및 설명을 입력 한 다음 만들기를 계속 클릭합니다.
  5. 옵션 : 아래에서 그랜트 프로젝트에이 서비스 계정 액세스가 서비스 계정에 부여 IAM 역할을 선택합니다.
  6. 계속을 클릭합니다.
  7. 옵션 :이 서비스 계정에서 부여 사용자 액세스, 사용 및 서비스 계정을 관리 할 수있는 사용자 또는 그룹을 추가합니다.
  8. 완료를 클릭합니다.
  9. 클릭 키를 만든 다음 만들기를 클릭합니다.

다음으로 서비스 계정 키를 만듭니다.

  1. 생성한 서비스 계정의 이메일 주소를 클릭합니다.
  2. 탭을 클릭합니다.
  3. 추가 키 드롭 다운 목록에서 새 키 만들기를 선택합니다.
  4. 만들기를 클릭합니다.

새 공개/개인 키 쌍이 생성되어 컴퓨터에 다운로드됩니다. 개인 키의 유일한 사본으로 사용됩니다. 안전하게 보관할 책임은 귀하에게 있습니다. 이 키 쌍을 분실한 경우 새 키를 생성해야 합니다.

언제든지 API Console로 돌아가서 이메일 주소, 공개 키 디지털 지문 및 기타 정보를 확인하거나 공개 키/비공개 키 쌍을 추가로 생성할 수 있습니다. API Console의 서비스 계정 사용자 인증 정보에 대한 자세한 내용은 API Console도움말 파일의 서비스 계정을 참조하세요.

서비스 계정의 이메일 주소를 확인하고 서비스 계정의 비공개 키 파일을 애플리케이션에서 액세스할 수 있는 위치에 저장하세요. 애플리케이션에 승인된 API를 호출해야 합니다.

서비스 계정에 도메인 차원 권한 위임

Google Workspace 계정이 있는 경우 조직의 관리자는 Google Workspace 도메인의 사용자를 대신하여 애플리케이션이 사용자 데이터에 액세스하도록 승인할 수 있습니다. 예를 들어 Google Calendar API를 사용하여 Google Workspace 도메인의 모든 사용자 캘린더에 일정을 추가하는 애플리케이션은 서비스 계정을 사용하여 사용자 대신 Google Calendar API에 액세스합니다. 도메인의 사용자를 대신하여 데이터에 액세스하도록 서비스 계정을 승인하는 것을 서비스 계정으로 '도메인 전체 권한 위임'이라고도 합니다.

서비스 계정에 도메인 전체 권한을 위임하려면 Google Workspace 도메인의 최고 관리자가 다음 단계를 완료해야 합니다.

  1. Google Workspace 도메인의 관리 콘솔에서 기본 메뉴 > 보안 및 하드웨어 및 API 제어 액세스 및 제어로 이동합니다.
  2. 도메인 전체 위임 창에서 도메인 전체 위임 관리를 선택합니다.
  3. 새로 추가를 클릭합니다.
  4. 클라이언트 ID 입력란에 서비스 계정의 클라이언트 ID를 입력합니다. Service accounts page에서 서비스 계정의 클라이언트 ID를 찾을 수 있습니다.
  5. OAuth 범위 (쉼표로 분리) 입력란에 애플리케이션에 액세스 권한을 부여해야 하는 범위 목록을 입력합니다. 예를 들어 애플리케이션에서 Google Drive API와 Google Calendar API에 대한 도메인 전체 액세스 권한을 필요로 하는 경우 https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar를 입력합니다.
  6. 승인을 클릭합니다.

이제 애플리케이션에 도메인의 사용자로 API를 호출할 수 있는 권한이 있습니다. 승인된 API 호출을 준비할 때 가장할 사용자를 지정합니다.

승인된 API 호출 준비

자바

API Console에서 클라이언트 이메일 주소와 비공개 키를 가져온 후 자바용 Google API 클라이언트 라이브러리를 사용하여 서비스 계정의 사용자 인증 정보 및 애플리케이션이 액세스해야 하는 범위에서 GoogleCredential 객체를 만듭니다. 예를 들면 다음과 같습니다.

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

Google Cloud Platform에서 앱을 개발하는 경우에는 애플리케이션 기본 사용자 인증 정보를 대신 사용하면 됩니다. 그러면 절차를 단순화할 수 있습니다.

도메인 전체 권한 위임

서비스 계정에 대한 도메인 전체 액세스 권한을 위임한 경우 사용자 계정을 가장하려면 GoogleCredential 객체의 createDelegated 메서드로 사용자 계정의 이메일 주소를 지정합니다. 예를 들면 다음과 같습니다.

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("user@example.com");

GoogleCredential 객체를 사용하여 애플리케이션에서 Google API를 호출합니다.

Python

API Console에서 클라이언트 이메일 주소와 비공개 키를 가져온 후 Python용 Google API 클라이언트 라이브러리를 사용하여 다음 단계를 완료합니다.

  1. 서비스 계정의 사용자 인증 정보 및 애플리케이션이 액세스해야 하는 범위에서 Credentials 객체를 만듭니다. 예를 들면 다음과 같습니다.
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/service.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

    Google Cloud Platform에서 앱을 개발하는 경우에는 애플리케이션 기본 사용자 인증 정보를 대신 사용하면 됩니다. 그러면 절차를 단순화할 수 있습니다.

  2. 도메인 전체 권한 위임

    서비스 계정에 대한 도메인 전체 액세스 권한을 위임한 경우 사용자 계정을 가장하려면 기존 ServiceAccountCredentials 객체의 with_subject 메서드를 사용합니다. 예를 들면 다음과 같습니다.

    delegated_credentials = credentials.with_subject('user@example.org')

사용자 인증 정보 객체를 사용하여 애플리케이션에서 Google API를 호출합니다.

HTTP/REST

API Console에서 클라이언트 ID와 비공개 키를 가져온 후 애플리케이션에서 다음 단계를 완료해야 합니다.

  1. 헤더, 클레임 세트, 서명이 포함된 JSON 웹 토큰 (JWT, 발음, "jot")을 만듭니다.
  2. Google OAuth 2.0 승인 서버에서 액세스 토큰을 요청합니다.
  3. 승인 서버가 반환하는 JSON 응답을 처리합니다.

다음 섹션에서는 이러한 단계를 완료하는 방법을 설명합니다.

응답에 액세스 토큰이 포함되어 있으면 액세스 토큰을 사용하여 Google API를 호출할 수 있습니다. (응답에 액세스 토큰이 포함되어 있지 않으면 JWT 및 토큰 요청의 형식이 올바르지 않거나 서비스 계정에 요청된 범위에 액세스할 권한이 없을 수 있습니다.)

액세스 토큰이 만료되면 애플리케이션에서 다른 JWT를 생성하고 서명한 후 다른 액세스 토큰을 요청합니다.

서버 애플리케이션에서 JWT를 사용하여 Google 승인 서버에 토큰을 요청한 다음 토큰을 사용하여 Google API 엔드포인트를 호출합니다. 최종 사용자는 관여하지 않습니다.

이 섹션의 나머지 부분에서는 JWT 만들기, JWT 서명, 액세스 토큰 요청 형식 작성, 응답 처리의 세부사항을 설명합니다.

JWT 만들기

JWT는 헤더, 클레임 세트, 서명이라는 세 부분으로 구성됩니다. 헤더 및 클레임 세트는 JSON 객체입니다. 이러한 JSON 객체는 UTF-8 바이트로 직렬화된 후 Base64url 인코딩을 사용하여 인코딩됩니다. 이 인코딩은 반복되는 인코딩 작업으로 인한 인코딩 변경에 대한 복원력을 제공합니다. 헤더, 클레임 세트, 서명은 마침표(.) 문자로 연결됩니다.

JWT는 다음과 같이 구성됩니다.

{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

서명의 기본 문자열은 다음과 같습니다.

{Base64url encoded header}.{Base64url encoded claim set}
JWT 헤더 구성

헤더는 서명 알고리즘과 어설션 형식을 나타내는 필드 두 개로 구성됩니다. 두 입력란 모두 필수 입력란이며 각 입력란에는 값이 1개만 있습니다. 추가 알고리즘과 형식이 도입되면 이 헤더가 변경됩니다.

서비스 계정은 RSA SHA-256 알고리즘 및 JWT 토큰 형식을 사용합니다. 따라서 헤더의 JSON 표현은 다음과 같습니다.

{"alg":"RS256","typ":"JWT"}

Base64url의 표현은 다음과 같습니다.

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
JWT 클레임 세트 구성

JWT 클레임 세트에는 요청된 권한 (범위), 토큰 대상, 발급기관, 토큰 발급 시간, 토큰 수명 등 JWT에 대한 정보가 포함됩니다. 대부분의 입력란은 필수입니다. JWT 헤더와 마찬가지로 JWT 클레임 세트는 JSON 객체이며 서명 계산에 사용됩니다.

필수 클레임

JWT 클레임 집합의 필수 클레임은 다음과 같습니다. 클레임 모음의 순서대로 표시될 수 있습니다.

이름 설명
iss 서비스 계정의 이메일 주소입니다.
scope 공백으로 구분된 애플리케이션에서 요청하는 권한 목록입니다.
aud 어설션의 대상 타겟에 관한 설명자 액세스 토큰을 요청할 때 이 값은 항상 https://oauth2.googleapis.com/token입니다.
exp 어설션의 만료 시간으로, 1970년 1월 1일 00:00:00 UTC 이후의 초로 지정됩니다. 이 값은 발급 후 최대 1시간입니다.
iat 어설션이 발급된 시간으로, 1970년 1월 1일 00:00:00 UTC 이후의 초로 지정됩니다.

다음은 JWT 클레임 집합에서 필수 필드의 JSON 표현입니다.

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/devstorage.read_only",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
추가 소유권 주장

기업에서 애플리케이션은 도메인 차원 위임을 사용하여 조직의 특정 사용자를 대신할 수 있습니다. 이러한 유형의 가장 권한을 수행할 수 있는 권한은 애플리케이션이 사용자를 가장할 수 있는 권한입니다. 이는 일반적으로 최고 관리자가 처리합니다. 자세한 내용은 도메인 전체 위임으로 API 액세스 제어를 참고하세요.

애플리케이션에 위임된 리소스에 대한 액세스 권한을 부여하는 액세스 토큰을 가져오려면 sub 필드의 값으로 설정된 JWT 클레임에 사용자의 이메일 주소를 포함합니다.

이름 설명
sub 애플리케이션에서 위임된 액세스 권한을 요청하는 사용자의 이메일 주소입니다.

애플리케이션에 사용자를 가장할 권한이 없으면 sub 필드가 포함된 액세스 토큰 요청에 대한 응답이 오류가 됩니다.

다음은 sub 필드가 포함된 JWT 클레임 집합의 예시입니다.

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub": "some.user@example.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
JWT 클레임 세트 인코딩

JWT 헤더와 마찬가지로 JWT 클레임 집합은 UTF-8 및 Base64url이 사용 가능한 상태로 인코딩되어야 합니다. 다음은 JWT 클레임 집합의 JSON 표현 예시입니다.

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
서명 계산

JSON 웹 서명(JWS)은 JWT의 서명을 생성하는 메커니즘을 안내하는 사양입니다. 서명의 입력은 다음 콘텐츠의 바이트 배열입니다.

{Base64url encoded header}.{Base64url encoded claim set}

서명을 계산할 때는 JWT 헤더의 서명 알고리즘을 사용해야 합니다. Google OAuth 2.0 승인 서버에서 지원하는 유일한 서명 알고리즘은 SHA-256 해싱 알고리즘을 사용하는 RSA입니다. 이는 JWT 헤더의 alg 필드에서 RS256로 표현됩니다.

SHA256withRSA(RSASSA-PKCS1-V1_5-SIGN(SHA-256 해시 함수로도 알려짐))를 사용하여 입력의 UTF-8 표현에 Google API Console에서 가져온 비공개 키로 서명합니다. 출력은 바이트 배열이 됩니다.

그러면 서명이 Base64url로 인코딩되어야 합니다. 헤더, 클레임 세트, 서명은 마침표(.) 문자로 연결됩니다. 그 결과 JWT가 생성됩니다. 이는 명확성을 위해 추가된 줄 바꿈이어야 합니다.

{Base64url encoded header}.
{Base64url encoded claim set}.
{Base64url encoded signature}

다음은 Base64url 인코딩 전의 JWT 예시입니다.

{"alg":"RS256","typ":"JWT"}.
{
"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://oauth2.googleapis.com/token",
"exp":1328554385,
"iat":1328550785
}.
[signature bytes]

다음은 서명되었으며 전송할 준비가 된 JWT의 예입니다.

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ

액세스 토큰 요청

서명된 JWT를 생성한 후 애플리케이션에서 이 인증서를 사용하여 액세스 토큰을 요청할 수 있습니다. 이 액세스 토큰 요청은 HTTPS POST 요청이며, 본문은 URL로 인코딩됩니다. URL은 다음과 같습니다.

https://oauth2.googleapis.com/token

HTTPS POST 요청에는 다음 매개변수가 필요합니다.

이름 설명
grant_type 필요에 따라 URL로 인코딩된 다음 문자열을 사용합니다. urn:ietf:params:oauth:grant-type:jwt-bearer
assertion 서명을 포함한 JWT

다음은 액세스 토큰 요청에서 사용되는 HTTPS POST 요청의 원시 덤프입니다.

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ

다음은 curl을 사용하는 동일한 요청입니다.

curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

응답 처리

JWT 및 액세스 토큰 요청의 형식이 올바르고 서비스 계정에 작업을 수행할 수 있는 권한이 있는 경우 승인 서버의 JSON 응답에 액세스 토큰이 포함됩니다. 다음은 응답의 예입니다.

{
  "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
  "scope": "https://www.googleapis.com/auth/prediction"
  "token_type": "Bearer",
  "expires_in": 3600
}

액세스 토큰은 expires_in 값으로 지정된 기간 동안 재사용할 수 있습니다.

Google API 호출

자바

다음 단계를 완료하여 GoogleCredential 객체를 사용하여 Google API를 호출합니다.

  1. GoogleCredential 객체를 사용하여 호출하려는 API의 서비스 객체를 만듭니다. 예:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. 서비스 객체에서 제공하는 인터페이스를 사용하여 API 서비스에 요청합니다. 예를 들어텍사스-example-123 프로젝트의 Cloud SQL 데이터베이스 인스턴스를 나열하려면 다음 안내를 따르세요.
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

다음 단계를 완료하여 승인된 Credentials 객체를 사용해 Google API를 호출할 수 있습니다.

  1. 호출하려는 API의 서비스 객체를 빌드합니다. API 이름과 승인된 Credentials 객체로 build 함수를 호출하여 서비스 객체를 빌드합니다. 예를 들어 Cloud SQL Administrative API의 버전 1beta3을 호출하려면 다음과 같이 합니다.
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. 서비스 객체에서 제공하는 인터페이스를 사용하여 API 서비스에 요청합니다. 예를 들어텍사스-example-123 프로젝트의 Cloud SQL 데이터베이스 인스턴스를 나열하려면 다음 안내를 따르세요.
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

애플리케이션이 액세스 토큰을 가져온 후 API에 필요한 액세스 범위가 부여된 경우 특정 서비스 계정 또는 사용자 계정을 대신하여 Google API를 호출하는 데 토큰을 사용할 수 있습니다. 이를 위해 access_token 쿼리 매개변수 또는 Authorization HTTP 헤더 Bearer 값을 포함하여 API 요청에 액세스 토큰을 포함합니다. 쿼리 문자열은 서버 로그에 표시되는 경향이 있으므로 HTTP 헤더를 사용하는 것이 좋습니다. 대부분의 경우 클라이언트 라이브러리를 사용하여 Google API 호출을 설정할 수 있습니다 (예: Drive 파일 API 호출).

OAuth 2.0 Playground에서 모든 Google API를 사용해 보고 범위를 확인할 수 있습니다.

HTTP GET 예시

Authorization: Bearer HTTP 헤더를 사용한 drive.files 엔드포인트 (Drive Files API) 호출은 다음과 같습니다. 다음과 같이 자체 액세스 토큰을 지정해야 합니다.

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

다음은 access_token 쿼리 문자열 매개변수를 사용하여 인증된 사용자를 대상으로 동일한 API를 호출한 내역입니다.

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl

이 명령어는 curl 명령줄 애플리케이션으로 테스트할 수 있습니다. 다음은 HTTP 헤더 옵션을 사용하는 예입니다 (권장).

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

또는 쿼리 문자열 매개변수 옵션을 선택할 수도 있습니다.

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

액세스 토큰이 만료되는 경우

Google OAuth 2.0 승인 서버에서 발급한 액세스 토큰은 expires_in 값에서 제공한 기간이 지나면 만료됩니다. 액세스 토큰이 만료되면 애플리케이션에서 다른 JWT를 생성하고 서명한 후 다른 액세스 토큰을 요청해야 합니다.

JWT 오류 코드

error 필드 error_description 필드 의미 해결 방법
unauthorized_client Unauthorized client or scope in request. 도메인 차원 위임을 사용하려고 하는 경우 서비스 계정은 사용자 도메인의 관리 콘솔에서 승인되지 않습니다.

sub 클레임 (관리)의 관리 콘솔에 대한 도메인 전체 위임 페이지에서 서비스 계정이 승인되었는지 확인합니다.

승인에 일반적으로 몇 분이 걸리지만 Google 계정의 모든 사용자에게 승인이 적용되려면 최대 24시간이 걸릴 수 있습니다.

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. 서비스 계정은 관리 콘솔에서 클라이언트 ID(숫자)가 아닌 클라이언트 이메일 주소를 사용하여 승인되었습니다. 관리 콘솔의 도메인 전체 위임 페이지에서 클라이언트를 삭제하고 숫자 ID로 다시 추가합니다.
access_denied (모든 값) 도메인 전체 위임 기능을 사용 중인 경우 요청된 범위 중 하나 이상이 관리 콘솔에서 승인되지 않습니다.

sub 클레임 (필드)에서 사용자에 대한 관리 콘솔의 도메인 전체 위임 페이지에서 서비스 계정이 승인되고 JWT의 scope 클레임에서 요청 중인 모든 범위가 포함되어 있는지 확인하세요.

승인에 일반적으로 몇 분이 걸리지만 Google 계정의 모든 사용자에게 승인이 적용되려면 최대 24시간이 걸릴 수 있습니다.

invalid_grant Not a valid email. 사용자가 존재하지 않습니다. sub 클레임 (필드)의 이메일 주소가 올바른지 확인하세요.
invalid_grant

Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your 'iat' and 'exp' values and use a clock with skew to account for clock differences between systems.

일반적으로 이는 현지 시스템 시간이 잘못되었음을 의미합니다. iat 값이 향후 exp 값이 65분 이상이거나 exp 값이 iat 값보다 낮은 경우에도 발생할 수 있습니다.

JWT가 생성된 시스템의 시계가 올바른지 확인합니다. 필요한 경우 시간을 Google NTP와 동기화하세요.

invalid_grant Invalid JWT Signature.

JWT 어설션은 클라이언트 이메일로 식별된 서비스 계정과 연결되지 않은 비공개 키로 서명되었거나 사용된 키가 삭제, 사용 중지 또는 만료되었습니다.

또는 JWT 어설션이 잘못 인코딩될 수도 있습니다. 줄바꿈이나 패딩 등 기호 없이 Base64로 인코딩해야 합니다.

JWT 클레임 세트를 디코딩하고 어설션에 서명한 키가 서비스 계정과 연결되어 있는지 확인합니다.

Google에서 제공하는 OAuth 라이브러리를 사용하여 JWT가 올바르게 생성되었는지 확인합니다.

invalid_scope Invalid OAuth scope or ID token audience provided. 요청된 범위가 없거나 (빈 범위 목록) 요청된 범위 중 하나가 존재하지 않습니다 (즉, 유효하지 않음).

JWT의 scope 클레임 (필드)이 채워졌는지 확인하고 포함된 API 범위를 사용하려는 API의 문서화된 범위와 비교하여 오류나 오타가 없는지 확인합니다.

scope 클레임의 범위 목록은 쉼표가 아닌 공백으로 구분해야 합니다.

disabled_client The OAuth client was disabled. JWT 어설션에 서명하는 데 사용된 키가 사용 중지됩니다.

Google API Console으로 이동하여 IAM 및amp; Admin > Service Accounts에서 어설션에 서명하는 데 사용한 "Key ID"가 포함된 서비스 계정을 사용 설정합니다.

부록: OAuth 없이 서비스 계정 승인

일부 Google API를 사용하면 OAuth 2.0 액세스 토큰 대신 서명된 JWT를 Bearer 토큰으로 직접 사용하여 승인된 API를 호출할 수 있습니다. 이 경우 API를 호출하기 전에 Google의 승인 서버에 네트워크 요청을 하지 않아도 됩니다.

호출하려는 API에 Google API GitHub 저장소에 게시된 서비스 정의가 있는 경우 액세스 토큰 대신 JWT를 사용하여 승인된 API를 호출할 수 있습니다. 방법은 다음과 같습니다.

  1. 위에 설명된 대로 서비스 계정 만들기 계정을 만들 때 가져오는 JSON 파일을 유지해야 합니다.
  2. jwt.io에서 제공되는 것과 같은 표준 JWT 라이브러리를 사용하여 다음 예시와 같이 헤더와 페이로드가 포함된 JWT를 만듭니다.
    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "abcdef1234567890"
    }
    .
    {
      "iss": "123456-compute@developer.gserviceaccount.com",
      "sub": "123456-compute@developer.gserviceaccount.com",
      "aud": "https://firestore.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600
    }
    • 헤더의 kid 필드에서 서비스 계정의 비공개 키 ID를 지정하세요. 서비스 계정 JSON 파일의 private_key_id 필드에서 이 값을 찾을 수 있습니다.
    • isssub 필드의 경우 서비스 계정의 이메일 주소를 지정합니다. 서비스 계정 JSON 파일의 client_email 필드에서 이 값을 찾을 수 있습니다.
    • aud 필드에 API 엔드포인트를 지정합니다. 예를 들면 https://SERVICE.googleapis.com/입니다.
    • iat 필드에는 현재 Unix 시간을 지정하고 exp 필드에는 JWT가 만료되는 정확한 시간을 3,600초 후에 지정합니다.

서비스 계정 JSON 파일에 있는 비공개 키를 사용하여 RSA-256으로 JWT에 서명합니다.

예를 들면 다음과 같습니다.

자바

google-api-java-clientjava-jwt를 사용합니다.

GoogleCredential credential =
        GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = credential.getServiceAccountPrivateKey();
String privateKeyId = credential.getServiceAccountPrivateKeyId();

long now = System.currentTimeMillis();

try {
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    String signedJwt = JWT.create()
        .withKeyId(privateKeyId)
        .withIssuer("123456-compute@developer.gserviceaccount.com")
        .withSubject("123456-compute@developer.gserviceaccount.com")
        .withAudience("https://firestore.googleapis.com/")
        .withIssuedAt(new Date(now))
        .withExpiresAt(new Date(now + 3600 * 1000L))
        .sign(algorithm);
} catch ...

Python

PyJWT를 사용하는 경우:

iat = time.time()
exp = iat + 3600
payload = {'iss': '123456-compute@developer.gserviceaccount.com',
           'sub': '123456-compute@developer.gserviceaccount.com',
           'aud': 'https://firestore.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers,
                       algorithm='RS256')
  1. 서명된 JWT를 Bearer 토큰으로 사용하여 API를 호출합니다.
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com