サーバー間アプリケーションに OAuth 2.0 を使用する

Google OAuth 2.0 システムは、ウェブ アプリケーションと Google サービス間の通信など、サーバー間のやり取りをサポートしています。このシナリオでは、サービス アカウントが必要です。これは、個々のエンドユーザーではなく、アプリケーションに属しているアカウントです。アプリケーションがサービス アカウントに代わって Google API を呼び出すため、ユーザーが直接関与する必要はありません。このシナリオは、「Two-legged OAuth」または「2LO」とも呼ばれます。(関連する用語「3-legged OAuth」は、アプリケーションがエンドユーザーに代わって Google API を呼び出すシナリオを指します。ユーザーは、同意が必要になる場合があります)。

通常、アプリケーションが Google API を使用してユーザーのデータではなく独自のデータを処理する場合、アプリケーションはサービス アカウントを使用します。たとえば、データの永続性に Google Cloud Datastore を使用するアプリケーションは、サービス アカウントを使用して Google Cloud Datastore API の呼び出しを認証します。

Google Workspace ドメイン管理者は、ドメイン内のユーザーに代わってユーザーデータにアクセスするサービス アカウントにドメイン全体の権限を付与することもできます。

このドキュメントでは、アプリケーションで Google API クライアント ライブラリ(推奨)または HTTP を使用して、サーバー間の OAuth 2.0 フローを完了する方法について説明します。

概要

サーバー間のやり取りをサポートするには、まず API Consoleでプロジェクトのサービス アカウントを作成します。Google Workspace アカウント内のユーザーのユーザーデータにアクセスするには、ドメイン全体のアクセスをサービス アカウントに委任します。

次に、アプリケーションはサービス アカウントの認証情報を使用して、OAuth 2.0 認証サーバーにアクセス トークンをリクエストし、承認済みの API 呼び出しを行う準備をします。

これで、アプリケーションはアクセス トークンを使用して Google API を呼び出すことができます。

サービス アカウントを作成する

サービス アカウントの認証情報には、生成された一意のメールアドレスと、1 つ以上の公開鍵/秘密鍵のペアが含まれます。ドメイン全体の委任が有効になっている場合、クライアント ID もサービス アカウントの認証情報に含まれます。

アプリケーションが Google App Engine で実行される場合、サービス アカウントはプロジェクトの作成時に自動的に設定されます。

アプリケーションが Google Compute Engine で実行される場合は、プロジェクトの作成時にサービス アカウントも自動的に設定されますが、Google Compute Engine インスタンスの作成時に、アプリケーションがアクセスする必要があるスコープを指定する必要があります。詳細については、サービス アカウントを使用するためのインスタンスの準備をご覧ください。

アプリケーションが Google App Engine や Google Compute Engine で実行されていない場合は、これらの認証情報を Google API Consoleで取得する必要があります。サービス アカウントの認証情報を生成するか、生成済みの公開認証情報を表示するには、次の操作を行います。

まず、サービス アカウントを作成します。

  1. Service accounts page開きます。
  2. If prompted, select a project, or create a new one.
  3. [サービス アカウントの作成] をクリックします。
  4. [サービス アカウントの詳細] で、サービス アカウントの名前、ID、説明を入力し、[作成して続行] をクリックします。
  5. オプション: [ Grant this service account access to project ] で、サービス アカウントに付与する IAM ロールを選択します。
  6. [続行]をクリックします。
  7. オプション: [ユーザーにこのサービス アカウントへのアクセスを許可する] で、サービス アカウントの使用と管理を許可するユーザーまたはグループを追加します。
  8. [完了]をクリックします。

次に、サービス アカウント キーを作成します。

  1. 作成したサービス アカウントのメール アドレスをクリックします。
  2. [キー] タブをクリックします。
  3. [キーの追加]ドロップダウン リストで、[新しいキーの作成]を選択します。
  4. [作成]をクリックします。

新しい公開鍵と秘密鍵のペアが生成され、マシンにダウンロードされます。秘密鍵の唯一のコピーとして機能します。あなたはそれを安全に保管する責任があります。このキー ペアを紛失した場合は、新しいキー ペアを生成する必要があります。

いつでも API Console に戻り、メールアドレス、公開鍵フィンガープリントなどの情報を確認できます。また、追加の公開鍵と秘密鍵のペアを生成することもできます。 API Consoleのサービス アカウントの認証情報の詳細については、 API Consoleヘルプファイルのサービス アカウントをご覧ください。

サービス アカウントのメールアドレスをメモし、サービス アカウントの秘密鍵ファイルをアプリケーションにアクセスできる場所に保存します。これらは、アプリケーションが承認済みの API 呼び出しを行うために必要です。

サービス アカウントにドメイン全体の権限を委任する

組織の Workspace 管理者は、Google Workspace アカウントを使用して、Google Workspace ドメインのユーザーに代わって Workspace ユーザーデータにアクセスするアプリケーションを認可できます。たとえば、Google Calendar API を使用して Google Workspace ドメイン内のすべてのユーザーのカレンダーに予定を追加するアプリケーションは、ユーザーに代わってサービス アカウントを使用して Google Calendar API にアクセスします。ドメイン内のユーザーに代わってデータにアクセスすることをサービス アカウントに認可することを、サービス アカウントに「ドメイン全体の権限の委任」と呼ぶこともあります。

ドメイン全体の権限をサービス アカウントに委任するには、Google Workspace ドメインの特権管理者が次の手順を行う必要があります。

  1. Google Workspace ドメインの 管理コンソールから、メインメニュー > [セキュリティ] > [アクセスとデータ管理] > [API の制御] に移動します。
  2. [ドメイン全体の委任] ペインで、[ドメイン全体の委任を管理] を選択します。
  3. [新しく追加] をクリックします。
  4. [クライアント ID] に、サービス アカウントのクライアント ID を入力します。サービス アカウントのクライアント ID は Service accounts pageで確認できます。
  5. [OAuth スコープ(カンマ区切り)] フィールドに、アプリケーションにアクセス権を付与する必要があるスコープのリストを入力します。たとえば、アプリケーションで Google Drive API と Google Calendar API へのドメイン全体の完全アクセス権が必要な場合は、「https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar」と入力します。
  6. [承認] をクリックします。

これで、アプリケーションに、Workspace ドメイン内のユーザーとして API 呼び出しを行う権限が付与されました(ユーザーの権限を借用できます)。このような委任された API 呼び出しを行う準備をするときに、権限を借用するユーザーを明示的に指定します。

委任された API 呼び出しの準備をする

Java

クライアントのメールアドレスと秘密鍵を API Consoleから取得したら、Java 用の 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("workspace-user@example.com");

上記のコードは、GoogleCredential オブジェクトを使用して createDelegated() メソッドを呼び出します。createDelegated() メソッドの引数には、Workspace アカウントに属するユーザーを指定する必要があります。リクエストを行うコードはこの認証情報を使用し、サービス アカウントを使用して 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')

Credentials オブジェクトを使用して、アプリケーションから Google API を呼び出します。

HTTP/REST

クライアント ID と秘密鍵を API Consoleから取得したら、アプリケーションで次の手順を行う必要があります。

  1. ヘッダー、クレームセット、署名を含む JSON ウェブトークン(JWT。発音)を作成します。
  2. Google OAuth 2.0 認可サーバーにアクセス トークンをリクエストします。
  3. 認可サーバーから返される JSON レスポンスを処理します。

以降のセクションでは、これらのステップを完了する方法について説明します。

レスポンスにアクセス トークンが含まれている場合は、そのアクセス トークンを使用して Google API を呼び出すことができます。(レスポンスにアクセス トークンが含まれていない場合、JWT とトークンのリクエストの形式が正しくないか、リクエストされたスコープにアクセスする権限がサービス アカウントにない可能性があります)。

アクセス トークンが期限切れになると、アプリケーションは別の JWT を生成し、それに署名して、別のアクセス トークンをリクエストします。

サーバー アプリケーションは、JWT を使用して Google 承認サーバーにトークンをリクエストし、そのトークンを使用して Google API エンドポイントを呼び出します。エンドユーザーは関与しません。

このセクションの残りの部分では、JWT の作成、JWT の署名、アクセス トークン リクエストの作成、レスポンスの処理の詳細について説明します。

JWT の作成

JWT は、ヘッダー、クレームセット、署名の 3 つの部分で構成されます。ヘッダーとクレーム セットは JSON オブジェクトです。これらの JSON オブジェクトは UTF-8 バイトにシリアル化され、Base64url エンコードでエンコードされます。このエンコードにより、エンコード オペレーションが繰り返されることによるエンコードの変更に耐えることができます。ヘッダー、クレームセット、署名は、ピリオド(.)文字で連結されます。

JWT は次のように構成されます。

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

署名のベース文字列は次のとおりです。

{Base64url encoded header}.{Base64url encoded claim set}
JWT ヘッダーの形成

ヘッダーは、署名アルゴリズム、アサーションの形式、JWT の署名に使用された [サービス アカウント キーのキー ID](https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts.keys) を示す 3 つのフィールドで構成されます。アルゴリズムと形式は必須です。各フィールドには値が 1 つのみです。アルゴリズムと形式が追加されると、それに応じてこのヘッダーが変更されます。キー ID は省略可能です。誤った鍵 ID が指定された場合、GCP はサービス アカウントに関連付けられているすべての鍵を試してトークンを検証し、有効な鍵が見つからない場合はトークンを拒否します。Google は、今後、キー ID が正しくないトークンを拒否する権限を有します。

サービス アカウントは、RSA SHA-256 アルゴリズムと JWT トークン形式に依存します。そのため、ヘッダーの JSON 表現は次のようになります。

{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}

これを Base64url で表すと、次のようになります。

          eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
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-safe でエンコードされるようにシリアル化する必要があります。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 Web Signature(JWS)は、JWT の署名の生成メカニズムをガイドする仕様です。シグネチャの入力は、次のコンテンツのバイト配列です。

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

署名を計算する際は、JWT ヘッダー内の署名アルゴリズムを使用する必要があります。Google OAuth 2.0 認可サーバーでサポートされている唯一の署名アルゴリズムは、SHA-256 ハッシュ アルゴリズムを使用する RSA です。これは、JWT ヘッダーの alg フィールドの RS256 として表現されます。

Google API Consoleから取得した秘密鍵と SHA256withRSA(SHA-256 ハッシュ関数で RSASSA-PKCS1-V1_5-SIGN とも呼ばれます)を使用して、入力の UTF-8 表現に署名します。出力はバイト配列になります。

署名は 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 の呼び出し

Java

GoogleCredential オブジェクトを使用して Google API を呼び出します。手順は次のとおりです。

  1. GoogleCredential オブジェクトを使用して、呼び出す API のサービス オブジェクトを作成します。次に例を示します。
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. サービス オブジェクトによって提供されるインターフェースを使用して、API サービスにリクエストを送信します。たとえば、ecommerce-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 Administration API のバージョン 1beta3 を呼び出すには、次のようにします。
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. サービス オブジェクトによって提供されるインターフェースを使用して、API サービスにリクエストを送信します。たとえば、ecommerce-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 ヘッダーを使用することをおすすめします。ほとんどの場合、Drive Files API を呼び出す場合などに、クライアント ライブラリを使用して Google 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 (任意の値) ドメイン全体の委任を使用している場合、リクエストされた 1 つ以上のスコープが管理コンソールで承認されていません。

管理コンソールの [ ドメイン全体の委任] ページで、sub クレーム(フィールド)のユーザーに対してサービス アカウントが承認されており、JWT の scope クレームにリクエストするすべてのスコープが含まれていることを確認します。

認可は通常数分で完了しますが、Google アカウントのすべてのユーザーに反映されるまでに最長で 24 時間かかることがあります。

admin_policy_enforced (任意の値) Google アカウントは、Google Workspace 管理者のポリシーにより、リクエストされた 1 つ以上のスコープを承認できません。

管理者がすべてのスコープ、または機密性の高いスコープと制限付きスコープに対するアクセスを、OAuth クライアント ID に明示的に付与するまで制限する方法の詳細については、Google Workspace 管理者のヘルプ記事 Google Workspace のデータにアクセスできるサードパーティ製アプリと内部アプリを制御するをご覧ください。

invalid_client (任意の値)

OAuth クライアントまたは JWT トークンが無効であるか、正しく構成されていません。

詳しくは、エラーの説明をご覧ください。

JWT トークンが有効であり、正しいクレームが含まれていることを確認します。

OAuth クライアントとサービス アカウントが正しく構成され、正しいメールアドレスを使用していることを確認してください。

JWT トークンが正しいこと、およびリクエストのクライアント ID に対して発行されていることを確認します。

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.

通常は、ローカル システムの時刻が正しくないことを意味します。また、exp 値が iat 値から 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. スコープがリクエストされていない(スコープの空のリスト)か、リクエストされたスコープの 1 つが存在しない(つまり無効)。

JWT の scope クレーム(フィールド)にデータが入力されていることを確認し、含まれているスコープと、使用する API のドキュメント化されたスコープを比較して、エラーや入力ミスがないことを確認します。

scope クレーム内のスコープのリストは、カンマではなくスペースで区切る必要があります。

disabled_client The OAuth client was disabled. JWT アサーションの署名に使用される鍵が無効になっています。

Google API Consoleに移動し、[IAM と管理] > [サービス アカウント] で、アサーションの署名に使用されるキー ID を含むサービス アカウントを有効にします。

org_internal This client is restricted to users within its organization. リクエストの OAuth クライアント ID は、アクセスを特定の Google Cloud 組織内の Google アカウントに限定するプロジェクトの一部です。

組織のサービス アカウントを使用して認証します。OAuth アプリケーションのユーザータイプの構成を確認します。

追加条項: OAuth を使用しないサービス アカウントの認証

一部の Google API では、OAuth 2.0 アクセス トークンではなく、署名済みの JWT を署名なしトークンとして直接使用して、承認済みの 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 フィールドで確認できます。
    • iss フィールドと sub フィールドに、サービス アカウントのメールアドレスを指定します。この値は、サービス アカウント JSON ファイルの client_email フィールドで確認できます。
    • aud フィールドに API エンドポイントを指定します。例: https://SERVICE.googleapis.com/
    • iat フィールドには現在の Unix 時刻を指定します。exp フィールドには、JWT が期限切れになる 3,600 秒後の時刻を指定します。

サービス アカウントの JSON ファイルにある秘密鍵を使用して、RSA-256 で JWT に署名します。

例:

Java

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 を署名なしトークンとして使用して、API を呼び出します。
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com