TV および入力機能が限られたデバイス アプリケーション用の OAuth 2.0

このドキュメントでは、テレビ、ゲーム機、プリンタなどのデバイスで実行されているアプリケーションから Google API にアクセスするために OAuth 2.0 認証を実装する方法について説明します。具体的には、このフローは、ブラウザにアクセスできないデバイス、または入力機能が制限されているデバイス向けに設計されています。

OAuth 2.0 では、ユーザー名やパスワードなどの情報を秘密にしたまま、ユーザーが特定のデータをアプリケーションと共有できます。たとえば、テレビ アプリケーションは OAuth 2.0 を使用して、Google ドライブに保存されているファイルを選択する権限を取得できます。

このフローを使用するアプリは個々のデバイスに配布されるため、アプリがシークレットを保持できないことが前提となります。ユーザーがアプリを使用しているとき、またはアプリがバックグラウンドで実行されているときに、Google API にアクセスできます。

代替手段

ブラウザと完全な入力機能にアクセスできる Android、iOS、macOS、Linux、Windows(ユニバーサル Windows プラットフォームを含む)などのプラットフォーム用のアプリを作成する場合は、モバイル アプリとデスクトップ アプリ用の OAuth 2.0 フローを使用します。(アプリがグラフィカル インターフェースのないコマンドライン ツールの場合でも、このフローを使用する必要があります)。

Google アカウントでユーザーにログインさせ、JWT ID トークンを使用して基本的なユーザー プロフィール情報を取得するだけの場合は、テレビと入力制限のあるデバイスでのログインをご覧ください。

前提条件

プロジェクトでAPI を有効にする

Google API を呼び出すアプリケーションは、 API Consoleでそれらの API を有効にする必要があります。

プロジェクトで API を有効にするには:

  1. Google API ConsoleのOpen the API Library
  2. If prompted, select a project, or create a new one.
  3. API Library には、利用可能なすべての API がプロダクト ファミリーと人気度に応じて分類されて表示されます。有効にする API がリストで見当たらない場合は、検索して見つけるか、その API が属するプロダクト ファミリーで [すべて表示] をクリックします。
  4. 有効にする API を選択し、[有効にする] ボタンをクリックします。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

承認認証情報を作成する

OAuth 2.0 を使用して Google API にアクセスするアプリケーションは、Google の OAuth 2.0 サーバーに対して自身の身元を示す認証情報を持つ必要があります。次の手順では、プロジェクトの認証情報を作成する方法について説明します。アプリケーションは、この認証情報を使用して、そのプロジェクトで有効にした API にアクセスできます。

  1. Go to the Credentials page.
  2. [Create Client] をクリックします。
  3. [テレビと入力が限られたデバイス] アプリケーション タイプを選択します。
  4. OAuth 2.0 クライアントに名前を付けて、[作成] をクリックします。

アクセス スコープを特定する

スコープを指定すると、アプリケーションからのアクセス要求は必要なリソースのみに限定されるようになり、ユーザーはアプリケーションに付与するアクセスレベルを制御できます。したがって、リクエストされるスコープの数とユーザーの同意を得られる可能性の間には逆相関がある可能性があります。

OAuth 2.0 認証の実装を開始する前に、アプリがアクセス権限を必要とするスコープを設定しておくことをおすすめします。

インストールされているアプリまたはデバイスの許可されているスコープのリストをご覧ください。

OAuth 2.0 アクセス トークンを取得する

アプリが入力機能が制限されたデバイスで実行される場合でも、ユーザーはこの認証フローを完了するために、入力機能が豊富なデバイスに別途アクセスする必要があります。このフローの手順は次のとおりです。

  1. アプリケーションは、アクセス権限をリクエストするスコープを識別するリクエストを Google の認可サーバーに送信します。
  2. サーバーは、デバイスコードやユーザーコードなど、後続のステップで使用される複数の情報を返します。
  3. ユーザーが別のデバイスで入力してアプリを承認できる情報を表示します。
  4. アプリは Google の認証サーバーへのポーリングを開始し、ユーザーがアプリを承認したかどうかを判断します。
  5. ユーザーが入力機能が豊富なデバイスに切り替え、ウェブブラウザを起動して、ステップ 3 で表示された URL に移動し、ステップ 3 で表示されたコードを入力します。ユーザーはアプリケーションへのアクセス権を付与(または拒否)できます。
  6. ポーリング リクエストに対する次のレスポンスには、ユーザーに代わってリクエストを承認するためにアプリが必要とするトークンが含まれています。(ユーザーがアプリへのアクセスを拒否した場合、レスポンスにトークンは含まれません)。

次の図は、このプロセスを示しています。

ブラウザを搭載した別のデバイスでログインする

以降のセクションで、これらの手順について詳しく説明します。デバイスが備える機能とランタイム環境は多岐にわたるため、このドキュメントで示す例では curl コマンドライン ユーティリティを使用します。これらの例は、さまざまな言語やランタイムに簡単に移植できる必要があります。

ステップ 1: デバイスコードとユーザーコードをリクエストする

このステップでは、デバイスが https://oauth2.googleapis.com/device/code の Google 認証サーバーに HTTP POST リクエストを送信します。このリクエストでは、アプリケーションと、ユーザーに代わってアプリケーションがアクセスを希望するアクセス スコープが識別されます。この URL は、device_authorization_endpoint メタデータ値を使用して、ディスカバリ ドキュメントから取得する必要があります。次の HTTP リクエスト パラメータを含めます。

パラメータ
client_id 必須

アプリケーションのクライアント ID。この値は、 にあります。

scope 必須

アプリケーションがユーザーの代わりにアクセスできるリソースを識別するスコープのスペース区切りリスト。これらの値は、Google がユーザーに表示する同意画面に反映されます。インストールされているアプリまたはデバイスの許可されているスコープのリストをご覧ください。

スコープを指定すると、アプリケーションからのアクセス要求は必要なリソースのみに限定されるようになり、ユーザーはアプリケーションに付与するアクセスレベルを制御できます。したがって、リクエストされるスコープの数とユーザーの同意が得られる可能性の間には逆相関があります。

次のスニペットは、リクエストの例を示しています。

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

client_id=client_id&scope=email%20profile

この例は、同じリクエストを送信する curl コマンドを示しています。

curl -d "client_id=client_id&scope=email%20profile" \
     https://oauth2.googleapis.com/device/code

ステップ 2: 認可サーバーのレスポンスを処理する

認可サーバーは、次のいずれかのレスポンスを返します。

成功のレスポンス

リクエストが有効な場合、レスポンスは次のプロパティを含む JSON オブジェクトになります。

プロパティ
device_code Google が一意に割り当てた値。認証をリクエストするアプリを実行しているデバイスを識別します。ユーザーは、より豊富な入力機能を備えた別のデバイスからそのデバイスを承認します。たとえば、ユーザーはノートパソコンやスマートフォンを使用して、テレビで実行されているアプリを承認できます。この場合、device_code はテレビを識別します。

このコードにより、アプリを実行しているデバイスは、ユーザーがアクセスを許可したか拒否したかを安全に判断できます。

expires_in device_codeuser_code の有効期間(秒数)。その間にユーザーが認証フローを完了せず、デバイスもユーザーの決定に関する情報を取得するためにポーリングを行わない場合は、ステップ 1 からこのプロセスを再開する必要があるかもしれません。
interval デバイスがポーリング リクエストの間で待機する時間(秒単位)。たとえば、値が 5 の場合、デバイスは 5 秒ごとに Google の認証サーバーにポーリング リクエストを送信する必要があります。詳しくは、ステップ 3 をご覧ください。
user_code アプリケーションがアクセスをリクエストしているスコープを Google に識別する、大文字と小文字が区別される値。ユーザー インターフェースでは、入力機能が豊富な別のデバイスでこの値を入力するようユーザーに指示します。Google はこの値を使用して、ユーザーにアプリへのアクセス権の付与を求める際に、正しいスコープのセットを表示します。
verification_url ユーザーが別のデバイスで移動して user_code を入力し、アプリへのアクセスを許可または拒否する必要がある URL。この値はユーザー インターフェースにも表示されます。

次のスニペットは、サンプル レスポンスを示しています。

{
  "device_code": "4/4-GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8",
  "user_code": "GQVQ-JKEC",
  "verification_url": "https://www.google.com/device",
  "expires_in": 1800,
  "interval": 5
}

割り当て超過レスポンス

デバイスコード リクエストがクライアント ID に関連付けられた割り当てを超えると、次のエラーを含む 403 レスポンスが返されます。

{
  "error_code": "rate_limit_exceeded"
}

その場合は、バックオフ戦略を使用してリクエストのレートを減らします。

ステップ 3: ユーザーコードを表示する

ステップ 2 で取得した verification_urluser_code をユーザーに表示します。どちらの値にも、US-ASCII 文字セットの印刷可能な文字を含めることができます。ユーザーに表示するコンテンツでは、別のデバイスの verification_url に移動して user_code を入力するようユーザーに指示する必要があります。

次のルールを念頭に置いてユーザー インターフェース(UI)を設計します。

  • user_code
    • user_code は、15 文字の「W」サイズを処理できるフィールドに表示する必要があります。つまり、コード WWWWWWWWWWWWWWW を正しく表示できる場合は、UI が有効です。UI で user_code がどのように表示されるかをテストする際は、その文字列値を使用することをおすすめします。
    • user_code では大文字と小文字が区別されるため、大文字と小文字の変更や他の書式設定文字の挿入など、一切変更しないでください。
  • verification_url
    • verification_url を表示するスペースは、40 文字の URL 文字列を処理できるだけの幅が必要です。
    • 表示用にスキームを削除する場合を除き、verification_url を変更しないでください。表示上の理由で URL からスキーム(https:// など)を削除する予定がある場合は、アプリが httphttps の両方のバリエーションを処理できることを確認してください。

ステップ 4: Google の認可サーバーをポーリングする

ユーザーは別のデバイスを使用して verification_url に移動し、アクセスを許可(または拒否)するため、ユーザーがアクセス リクエストに応答しても、リクエスト元のデバイスに自動的に通知されることはありません。そのため、リクエスト元のデバイスは、ユーザーがリクエストに応答したタイミングを判断するために、Google の認証サーバーをポーリングする必要があります。

リクエスト元のデバイスは、ユーザーがアクセス リクエストに応答したことを示すレスポンスを受け取るまで、または ステップ 2 で取得した device_codeuser_code の有効期限が切れるまで、ポーリング リクエストを送信し続ける必要があります。ステップ 2 で返された interval は、リクエスト間の待機時間(秒単位)を指定します。

ポーリングするエンドポイントの URL は https://oauth2.googleapis.com/token です。ポーリング リクエストには次のパラメータが含まれます。

パラメータ
client_id アプリケーションのクライアント ID。この値は、 にあります。
client_secret 指定された client_id のクライアント シークレット。この値は、 にあります。
device_code ステップ 2 で認可サーバーから返された device_code
grant_type urn:ietf:params:oauth:grant-type:device_code に設定します。

次のスニペットは、リクエストの例を示しています。

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

client_id=client_id&
client_secret=client_secret&
device_code=device_code&
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code

この例は、同じリクエストを送信する curl コマンドを示しています。

curl -d "client_id=client_id&client_secret=client_secret& \
         device_code=device_code& \
         grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code" \
         -H "Content-Type: application/x-www-form-urlencoded" \
         https://oauth2.googleapis.com/token

ステップ 5: ユーザーがアクセス リクエストに応答する

次の画像は、ステップ 3 で表示した verification_url に移動したときにユーザーに表示されるページに似たページを示しています。

コードを入力してデバイスを接続する

user_code を入力し、まだログインしていない場合は Google にログインすると、以下のような同意画面が表示されます。

デバイス クライアントの同意画面の例

ステップ 6: ポーリング リクエストへのレスポンスを処理する

Google の認可サーバーは、各ポーリング リクエストに対して次のいずれかのレスポンスを返します。

アクセス権が付与されました

ユーザーがデバイスへのアクセスを許可した場合(同意画面で Allow をクリックした場合)、レスポンスにはアクセス トークンと更新トークンが含まれます。トークンを使用すると、デバイスはユーザーに代わって Google API にアクセスできます。(レスポンスの scope プロパティは、デバイスがアクセスできる API を決定します)。

この場合、API レスポンスには次のフィールドが含まれます。

フィールド
access_token Google API リクエストを承認するためにアプリケーションが送信するトークン。
expires_in アクセス トークンの残りの有効期間(秒単位)。
refresh_token 新しいアクセス トークンを取得するために使用できるトークン。更新トークンは、ユーザーがアクセスを取り消すか、更新トークンの有効期限が切れるまで有効です。デバイスに対しては常にリフレッシュ トークンが返されることに注意してください。
refresh_token_expires_in 更新トークンの残りの有効期間(秒単位)。この値は、ユーザーが時間ベースのアクセスを許可した場合にのみ設定されます。
scope access_token によって付与されたアクセス権のスコープ。スペース区切りの大文字と小文字が区別される文字列のリストとして表現されます。
token_type 返されるトークンのタイプ。この時点では、このフィールドの値は常に Bearer に設定されます。

次のスニペットは、サンプル レスポンスを示しています。

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
  "token_type": "Bearer",
  "refresh_token": "1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

アクセス トークンの有効期間は限られています。アプリケーションが API に長期間アクセスする必要がある場合は、更新トークンを使用して新しいアクセス トークンを取得できます。アプリケーションでこのタイプのアクセスが必要な場合は、後で使用するために更新トークンを保存する必要があります。

アクセスが拒否されました

ユーザーがデバイスへのアクセスを拒否した場合、サーバー レスポンスには 403 HTTP レスポンス ステータス コード(Forbidden)が含まれます。レスポンスには次のエラーが含まれます。

{
  "error": "access_denied",
  "error_description": "Forbidden"
}

承認待ち

ユーザーがまだ認証フローを完了していない場合、サーバーは 428 HTTP レスポンス ステータス コード(Precondition Required)を返します。レスポンスには次のエラーが含まれます。

{
  "error": "authorization_pending",
  "error_description": "Precondition Required"
}

ポーリングの頻度が高すぎる

デバイスがポーリング リクエストを頻繁に送信すると、サーバーは 403 HTTP レスポンス ステータス コード(Forbidden)を返します。レスポンスには次のエラーが含まれます。

{
  "error": "slow_down",
  "error_description": "Forbidden"
}

その他のエラー

認可サーバーは、ポーリング リクエストに必要なパラメータが欠落している場合や、パラメータ値が正しくない場合にもエラーを返します。通常、これらのリクエストには 400Bad Request)または 401Unauthorized)の HTTP レスポンス ステータス コードが含まれます。エラーには次のようなものがあります。

エラー HTTP ステータス コード 説明
admin_policy_enforced 400 Google アカウントの Google Workspace 管理者のポリシーにより、リクエストされた 1 つ以上のスコープを承認できません。管理者が OAuth クライアント ID に明示的にアクセス権を付与するまで、スコープへのアクセスを制限する方法について詳しくは、Google Workspace 管理者向けヘルプ記事の Google Workspace のデータにアクセスできるサードパーティ製アプリと内部アプリを制御するをご覧ください。
invalid_client 401

OAuth クライアントが見つかりませんでした。たとえば、client_id パラメータの値が無効な場合、このエラーが発生します。

OAuth クライアント タイプが正しくありません。クライアント ID のアプリケーション タイプが [テレビと入力制限付きデバイス] に設定されていることを確認します。

invalid_grant 400 code パラメータ値が無効であるか、すでに使用されているか、解析できません。
unsupported_grant_type 400 grant_type パラメータの値が無効です。
org_internal 403 リクエスト内の OAuth クライアント ID は、特定の Google Cloud 組織内の Google アカウントへのアクセスを制限するプロジェクトの一部です。OAuth アプリケーションのユーザータイプの構成を確認します。

Google API の呼び出し

アプリケーションがアクセス トークンを取得した後、API で必要なアクセス スコープが付与されている場合は、トークンを使用して特定のユーザー アカウントの代わりに Google API を呼び出すことができます。これを行うには、access_token クエリ パラメータまたは Authorization HTTP ヘッダー Bearer 値のいずれかを含めることで、API へのリクエストにアクセス トークンを含めます。クエリ文字列はサーバーログに表示される傾向があるため、可能な場合は HTTP ヘッダーを使用することをおすすめします。ほとんどの場合、クライアント ライブラリを使用して Google API への呼び出しを設定できます(たとえば、Drive Files API を呼び出す場合など)。

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

HTTP GET の例

Authorization: Bearer HTTP ヘッダーを使用して 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

アクセス トークンをリフレッシュする

アクセス トークンは定期的に期限が切れ、関連する API リクエストに対して無効な認証情報になります。トークンに関連付けられたスコープへのオフライン アクセスをリクエストした場合は、ユーザーに権限を求めることなく(ユーザーが不在の場合を含めて)アクセス トークンを更新できます。

アクセス トークンを更新するには、アプリケーションが次のパラメータを含む HTTPS POST リクエストを Google の認証サーバー(https://oauth2.googleapis.com/token)に送信します。

フィールド
client_id API Consoleから取得したクライアント ID。
client_secret API Consoleから取得したクライアント シークレット。
grant_type OAuth 2.0 仕様で定義されているように、このフィールドの値は refresh_token に設定する必要があります。
refresh_token 認証コード交換から返された更新トークン。

次のスニペットは、リクエストの例を示しています。

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

client_id=your_client_id&
client_secret=your_client_secret&
refresh_token=refresh_token&
grant_type=refresh_token

ユーザーがアプリケーションに付与したアクセス権を取り消していない限り、トークン サーバーは新しいアクセス トークンを含む JSON オブジェクトを返します。次のスニペットは、サンプル レスポンスを示しています。

{
  "access_token": "1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in": 3920,
  "scope": "https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/calendar.readonly",
  "token_type": "Bearer"
}

発行される更新トークンの数には上限があります。クライアントとユーザーの組み合わせごとに 1 つ、すべてのクライアントのユーザーごとに 1 つです。更新トークンは長期ストレージに保存し、有効な限り使用し続ける必要があります。アプリケーションが過剰な数の更新トークンをリクエストすると、これらの上限に達する可能性があります。その場合、古い更新トークンは機能しなくなります。

トークンの取り消し

ユーザーがアプリに付与したアクセス権を取り消したい場合もあります。ユーザーは、 アカウント設定にアクセスしてアクセス権を取り消すことができます。詳しくは、アカウントにアクセスできるサードパーティのサイトやアプリのサポート ドキュメントの「サイトやアプリのアクセス権を削除する」セクションをご覧ください。

アプリケーションが、自身に付与されたアクセス権をプログラムで取り消すことも可能です。プログラムによる取り消しは、ユーザーが登録を解除した場合、アプリを削除した場合、アプリに必要な API リソースが大幅に変更された場合などに重要です。つまり、削除プロセスの一部として、以前にアプリに付与された権限が削除されるように API リクエストを含めることができます。

プログラムでトークンを取り消すには、アプリケーションが https://oauth2.googleapis.com/revoke にリクエストを送信し、トークンをパラメータとして含めます。

curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
        https://oauth2.googleapis.com/revoke?token={token}

トークンはアクセス トークンまたは更新トークンです。トークンがアクセス トークンで、対応する更新トークンがある場合、更新トークンも取り消されます。

取り消しが正常に処理されると、レスポンスの HTTP ステータス コードは 200 になります。エラー条件の場合、エラーコードとともに HTTP ステータス コード 400 が返されます。

許可されたスコープ

デバイスの OAuth 2.0 フローは、次のスコープでのみサポートされています。

OpenID ConnectGoogle ログイン

  • email
  • openid
  • profile

Drive API

  • https://www.googleapis.com/auth/drive.appdata
  • https://www.googleapis.com/auth/drive.file

YouTube API

  • https://www.googleapis.com/auth/youtube
  • https://www.googleapis.com/auth/youtube.readonly

時間に基づくアクセス

時間ベースのアクセスでは、ユーザーはアクションを完了するために、アプリが期間限定でデータにアクセスすることを許可できます。時間ベースのアクセスは、同意フロー中に一部の Google サービスで利用できます。ユーザーは、限られた期間のみアクセスを許可するオプションを選択できます。たとえば、 Data Portability API を使用すると、データを 1 回だけ転送できます。

ユーザーがアプリに時間ベースのアクセス権を付与すると、更新トークンは指定された期間の経過後に期限切れになります。特定の状況下では、更新トークンが早期に無効になることがあります。詳しくは、こちらのケースをご覧ください。このような場合、認可コード交換レスポンスで返される refresh_token_expires_in フィールドは、更新トークンの有効期限が切れるまでの残り時間を表します。

クロスアカウント保護機能の実装

ユーザーのアカウントを保護するために行うべき追加の手順として、Google のクロス アカウント保護サービスを利用してクロス アカウント保護を実装することが挙げられます。このサービスでは、ユーザー アカウントの大きな変更に関する情報をアプリケーションに提供するセキュリティ イベント通知を登録できます。この情報を使用して、イベントへの対応方法に応じてアクションを実行できます。

Google のクロス アカウント保護サービスからアプリに送信されるイベントタイプの例を次に示します。

  • https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
  • https://schemas.openid.net/secevent/oauth/event-type/token-revoked
  • https://schemas.openid.net/secevent/risc/event-type/account-disabled

クロスアカウント保護の実装方法と利用可能なイベントの完全なリストについては、 クロスアカウント保護でユーザー アカウントを保護する をご覧ください。