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

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。
全アセットの再ビルドが必要詳細については、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 で実行されていない場合は、これらの認証情報を で取得する必要があります。サービス アカウントの認証情報を生成する、または生成済みの公開認証情報を表示するには、次のようにします。

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

  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 呼び出しが許可されるようにするには、承認済みの API 呼び出しを行う必要があります。

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

Google Workspace アカウントをお持ちの場合、組織の管理者は、Google Workspace ドメインのユーザーに代わってユーザーデータにアクセスするアプリケーションを認可できます。たとえば、Google カレンダー API を使用して Google Workspace ドメイン内のすべてのユーザーのカレンダーに予定を追加するアプリケーションでは、サービス アカウントを使用してユーザーの代わりに Google カレンダー 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')

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

HTTP/REST

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

  1. ヘッダー、クレームセット、署名を含む JSON Web Token(JWT、発音、「jot」)を作成します。
  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 ヘッダーの形成

ヘッダーは、署名アルゴリズムとアサーションの形式を示す 2 つのフィールドで構成されます。どちらのフィールドも必須で、各フィールドの値は 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 アクセスを制御するをご覧ください。

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

名前 説明
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 Authorization Server でサポートされている唯一の署名アルゴリズムは、SHA-256 ハッシュ アルゴリズムを使用した RSA です。これは JWT ヘッダーの alg フィールドで RS256 として表されます。

SHA256withRSA(SHA-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 リクエストには次のパラメータが必要です。

名前 説明
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 サービスに対するリクエストを行います。たとえば、difk-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 サービスに対するリクエストを行います。たとえば、difk-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 > Service Accounts] で、「アサーションの署名に使用する鍵 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 秒後の時刻を指定します。

サービス アカウントの 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