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

174詳細については、Google Cloud Platform ドキュメントの認証の概要をご覧ください。

Google OAuth 2.0 システムでは、ウェブ アプリケーションと Google サービス間のサーバー間インタラクションなどがサポートされます。このシナリオでは、サービス アカウントが必要です。これは、個々のエンドユーザーではなくアプリケーションに属するアカウントです。アプリケーションがサービス アカウントに代わって Google API を呼び出すため、ユーザーが直接関与する必要はありません。このシナリオは「2-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 フローを完了する方法について説明します。

概要

サーバー間のインタラクションをサポートするには、まず でプロジェクトのサービス アカウントを作成します。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 で実行されていない場合は、これらの認証情報を で取得する必要があります。サービス アカウントの認証情報を生成する、またはユーザーが生成した公開認証情報を表示するには、次のようにします。

First, create a service account:

  1. Open the Service accounts page.
  2. If prompted, select a project, or create a new one.
  3. Click  Create service account.
  4. Under Service account details, type a name, ID, and description for the service account, then click Create and continue.
  5. Optional: Under Grant this service account access to project, select the IAM roles to grant to the service account.
  6. Click Continue.
  7. Optional: Under Grant users access to this service account, add the users or groups that are allowed to use and manage the service account.
  8. Click Done.
  9. Click  Create key, then click Create.

Next, create a service account key:

  1. Click the email address for the service account you created.
  2. Click the Keys tab.
  3. In the Add key drop-down list, select Create new key.
  4. Click Create.

Your new public/private key pair is generated and downloaded to your machine; it serves as the only copy of the private key. You are responsible for storing it securely. If you lose this key pair, you will need to generate a new one.

いつでも 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. [Add new] をクリックします。
  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. [承認] をクリックします。

アプリケーションで、ドメイン内のユーザーとして(ユーザーの権限借用として)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("user@example.com");

アプリケーションで Google API を呼び出すには、GoogleCredential オブジェクトを使用します。

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

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

  1. ヘッダー、クレームセット、署名を含む JSON ウェブトークン(JWT、発音、&t&tt)を作成します。
  2. Google OAuth 2.0 認証サーバーにアクセス トークンをリクエストします。
  3. Authorization サーバーが返す 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 ヘッダーの形成

ヘッダーは、署名アルゴリズムとアサーションの形式を示す 2 つのフィールドで構成されます。どちらのフィールドも必須であり、各フィールドの値は 1 つのみです。追加のアルゴリズムと形式が導入されると、それに応じてヘッダーも変わります。

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

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

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

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
JWT クレームセットの形成

JWT クレームセットには、リクエストされている権限(スコープ)、トークンのターゲット、発行者、トークンの発行時刻、トークンの有効期間など、JWT に関する情報が含まれています。ほとんどの欄は必須です。JWT ヘッダーと同様に、JWT クレームセットは JSON オブジェクトであり、署名の計算に使用されます。

必須クレーム

JWT クレームセットに必要なクレームを以下に示します。クレーム セットの任意の順序で表示できます。

名前 Description
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 アクセスを制御するをご覧ください。

リソースへの委任アクセス権をアプリケーションに付与するアクセス トークンを取得するには、JWT クレームのユーザーのメールアドレスを sub フィールドの値として設定します。

名前 Description
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 Web Signature(JWS)は、JWT の署名を生成するメカニズムを指示する仕様です。署名の入力は、次のコンテンツのバイト配列です。

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

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

SHA256withRSA(SHAS-256 ハッシュ関数による RSASSA-PKCS1-V1_5-SIGN とも呼ばれる)で、 Google API Consoleから取得した秘密鍵を使用して、入力の 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 リクエストでは、次のパラメータが必要です。

名前 Description
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 サービスへのリクエストを行います。たとえば、Fitbit-example-123 プロジェクト内の Cloud SQL データベースのインスタンスを一覧表示するには、次のようにします。
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

承認済みの Credentials オブジェクトを使用して、次の手順で Google API を呼び出します。

  1. 呼び出す API のサービス オブジェクトをビルドします。サービス オブジェクトを作成するには、build 関数を呼び出して、API の名前と承認済みの Credentials オブジェクトおよびバージョンを指定します。たとえば、Cloud SQL Administration API のバージョン 1beta3 を呼び出すには、次のようにします。
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. サービス オブジェクトで提供されるインターフェースを使用して API サービスへのリクエストを行います。たとえば、Fitbit-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 Files API を呼び出す場合など)。

すべての Google API を試して、OAuth 2.0 Playground でスコープを確認できます。

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 時間かかることがあります。

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 / Admin アカウント] で、アサーションの署名に使用する「鍵 ID」を含むサービス アカウントを有効にします。

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

一部の Google API では、OAuth 2.0 アクセス トークンではなく、署名なし JWT を署名なしトークンとして直接使用して、承認済みの API 呼び出しを行うことができます。これにより、API 呼び出しを行う前に Google の承認サーバーにネットワーク リクエストを行う必要がなくなります。

呼び出す API に Google API GitHub リポジトリで公開されているサービス定義が存在する場合は、アクセス トークンの代わりに JWT を使用して承認済みの API 呼び出しを行うことができます。手順は以下のとおりです。

  1. 上述の手順でサービス アカウントを作成します。アカウントを作成する際は、取得された JSON ファイルを必ず保持してください。
  2. 標準的な JWT ライブラリ(jwt.io にあるものなど)を使用して、次の例のようにヘッダーとペイロードを含む 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 秒後の時刻を指定します。

RSA-256 を使用し、サービス アカウントの JSON ファイルにある秘密鍵を使用して 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. 署名付きトークンを署名なしトークンとして使用して API を呼び出します。
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com