サーバー間アプリケーションにOAuth2.0を使用する

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

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

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

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

概要概要

サーバー間の相互作用をサポートするには、最初にAPI Consoleでプロジェクトのサービスアカウントを作成します。 Google Workspaceアカウントのユーザーのユーザーデータにアクセスする場合は、ドメイン全体のアクセスをサービスアカウントに委任します。

次に、アプリケーションは、サービスアカウントの資格情報を使用して、OAuth 2.0認証サーバーからアクセストークンを要求することにより、承認されたAPI呼び出しを行う準備をします。

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

サービスアカウントの作成

サービスアカウントのクレデンシャルには、一意の生成された電子メールアドレスと、少なくとも1つの公開鍵と秘密鍵のペアが含まれます。ドメイン全体の委任が有効になっている場合、クライアントIDもサービスアカウントの資格情報の一部になります。

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

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

アプリケーションがGoogleAppEngineまたはGoogleCompute Engineで実行されていない場合は、Google API Consoleでこれらの認証情報を取得する必要があります。サービスアカウントのクレデンシャルを生成する、またはすでに生成したパブリッククレデンシャルを表示するには、次の手順を実行します。

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

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

G Suiteドメイン全体の権限をサービスアカウントに付与する必要がある場合は、作成したサービスアカウントのメールアドレスをクリックし、[ 一意のID]ボックスから値をコピーします。

権限をサービスアカウントに委任するには、コピーした値をクライアントIDとして使用します。

いつでもAPI Consoleに戻って、電子メールアドレス、公開鍵の指紋、およびその他の情報を表示したり、追加の公開鍵と秘密鍵のペアを生成したりできます。 API Consoleのサービスアカウントの資格情報の詳細については、API Consoleヘルプファイルの サービスアカウントを参照してください。

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

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

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

ドメイン全体の権限をサービスアカウントに委任するには、最初にService accounts pageの既存のサービスアカウントに対してドメイン全体の委任を有効にするか、ドメイン全体の委任を有効にして新しいサービスアカウント作成します。

次に、Google Workspaceドメインのスーパー管理者は、次の手順を実行する必要があります。

  1. Google Workspaceドメインの管理コンソールから[メインメニュー > [セキュリティ > [APIコントロール移動します
  2. [ドメイン全体の委任]ペインで、[ドメイン全体の委任の管理]を選択します。
  3. [新規追加]をクリックします。
  4. [クライアントID]フィールドに、サービスアカウントのクライアントIDを入力します。サービスアカウントのクライアントIDはService accounts pageにあります。
  5. [ OAuthスコープ(カンマ区切り)]フィールドに、アプリケーションにアクセスを許可する必要があるスコープのリストを入力します。たとえば、アプリケーションでGoogleドライブAPIとGoogleカレンダー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");

GoogleCredentialオブジェクトを使用して、 GoogleCredentialを呼び出します。

Python

API Consoleからクライアントのメールアドレスと秘密鍵を取得したら、 Python用のGoogleAPI クライアントライブラリを使用して次の手順を実行します。

  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オブジェクトを使用して、アプリケーションでGoogleAPIを呼び出します。

HTTP / REST

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

  1. ヘッダー、クレームセット、および署名を含むJSON Webトークン(JWT、発音、「jot」)を作成します。
  2. Google OAuth2.0認証サーバーにアクセストークンをリクエストします。
  3. AuthorizationServerが返すJSON応答を処理します。

次のセクションでは、これらの手順を完了する方法について説明します。

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

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

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

このセクションの残りの部分では、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つの値しかありません。追加のアルゴリズムとフォーマットが導入されると、このヘッダーはそれに応じて変更されます。

サービスアカウントは、RSASHA-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:00UTCからの秒数で指定されます。この値の最大値は発行時刻から1時間後です。
iatアサーションが発行された時刻。1970年1月1日00:00:00UTCからの秒数として指定されます。

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

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

署名を計算するときは、JWTヘッダーの署名アルゴリズムを使用する必要があります。 Google OAuth 2.0 Authorization Serverでサポートされている唯一の署名アルゴリズムは、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を生成した後、アプリケーションはそれを使用してアクセストークンを要求できます。このアクセストークンリクエストはPOSTリクエストであり、本文はURLエンコードされています。 URLを以下に示します。

https://oauth2.googleapis.com/token

HTTPS POSTリクエストには、次のパラメータが必要です。

名前説明
grant_type次の文字列を使用し、必要に応じてURLエンコードしますurn:ietf:params:oauth:grant-type:jwt-bearer
assertion署名を含むJWT。

以下は、アクセストークンリクエストで使用される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値で指定された期間中に再利用できます。

GoogleAPIの呼び出し

Java

次の手順を実行して、 GoogleCredentialオブジェクトを使用してGoogleCredentialを呼び出します。

  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オブジェクトを使用してCredentialsを呼び出します。

  1. 呼び出すAPIのサービスオブジェクトを作成します。 APIの名前とバージョン、および承認されたCredentialsオブジェクトを使用してbuild関数を呼び出すことにより、サービスオブジェクトをbuildます。たとえば、Cloud SQL Administration 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に必要なアクセス範囲が付与されている場合は、トークンを使用して、特定のサービスアカウントまたはユーザーアカウントに代わってGoogleAPIを呼び出すことができます。これを行うには、 access_tokenクエリパラメーターまたはAuthorization HTTPヘッダーBearer値のいずれかを含めて、APIへのリクエストにアクセストークンを含めます。クエリ文字列はサーバーログに表示される傾向があるため、可能な場合はHTTPヘッダーを使用することをお勧めします。ほとんどの場合、クライアントライブラリを使用してGoogle APIへの呼び出しを設定できます(たとえば、 Drive Files APIを呼び出す場合)。

OAuth 2.0PlaygroundですべてのGoogleAPIを試して、そのスコープを表示できます。

HTTPGETの例

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 Authorization Serverによって発行されたアクセストークンは、 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分以上iat場合、またはexp値がiat値よりも低い場合にも発生する可能性があります。

JWTが生成されるシステムのクロックが正しいことを確認してください。必要に応じて、時間をGoogleNTPと同期します。

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クレームscopeのスコープのリストは、コンマではなくスペースで区切る必要があることに注意してください。

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

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

補遺:OAuthなしのサービスアカウント認証

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

呼び出すAPIのサービス定義がGoogleAPI 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が期限切れになる正確に3600秒後の時刻を指定します。

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