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

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

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

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

代替手段

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

前提条件

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

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

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

  1. Google API Console で API ライブラリを開きます。
  2. プロンプトが表示されたら、プロジェクトのいずれかを選択するか、新しいプロジェクトを作成します。
  3. API ライブラリには、利用可能なすべての API がプロダクト ファミリーと人気度に応じてグループ化されて表示されます。有効にする API がリストで見当たらない場合は、検索して見つけるか、その API が属するプロダクト ファミリーの [すべて表示] をクリックします。
  4. 有効にする API を選択し、[有効にする] ボタンをクリックします。
  5. プロンプトが表示されたら、請求機能を有効にします。
  6. プロンプトが表示されたら、API の利用規約を確認し、同意します。

承認認証情報を作成する

OAuth 2.0 を使用して Google API にアクセスするアプリケーションには、Google の OAuth 2.0 サーバーにアプリケーションを識別させる認証情報が必要です。プロジェクトの認証情報を作成する手順は次のとおりです。アプリケーションは、認証情報を使用して、そのプロジェクトで有効にした API にアクセスできます。

  1. [クライアント] ページに移動します。
  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。この値は、Cloud コンソールの [クライアント] ページで確認できます。

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_code と user_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_url と user_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:// など)を削除する場合は、アプリが http と https の両方のバリアントを処理できるようにしてください。

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

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

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

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

パラメータ
client_id アプリケーションのクライアント ID。この値は、Cloud コンソールの [クライアント] ページで確認できます。
client_secret 指定された client_id のクライアント シークレット。この値は、Cloud コンソールの [クライアント] ページで確認できます。
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 新しいアクセス トークンの取得に使用できるトークン。更新トークンは、ユーザーがアクセスを取り消すか、更新トークンの有効期限が切れるまで有効です。更新トークンは常にデバイスに返されます。
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"
}

その他のエラー

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

エラー HTTP ステータス コード 説明
admin_policy_enforced 400 Google Workspace 管理者のポリシーにより、Google アカウントはリクエストされた 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 エンドポイント(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 リクエストに対して無効な認証情報になります。トークンに関連付けられたスコープへのオフライン アクセスをリクエストした場合は、ユーザーに権限を求めることなく(ユーザーが不在の場合を含めて)アクセス トークンを更新できます。

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

名前 値
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&
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 つの上限があり、すべてのクライアントにわたってユーザーごとに別の上限があります。更新トークンは長期ストレージに保存し、有効期限が切れるまで使用し続ける必要があります。アプリケーションがリクエストする更新トークンが多すぎると、この上限に達する可能性があります。その場合、古い更新トークンは機能しなくなります。

トークン失効

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

アプリケーションは、プログラムによって、付与されたアクセス権を取り消すこともできます。 プログラムによる取り消しは、ユーザーが登録を解除した場合、アプリケーションを削除した場合、アプリに必要な 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 Connect、Google ログイン

  • 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

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