テレビや制限付き入力デバイス アプリケーション用の OAuth 2.0

174

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

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

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

代替方法

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

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

Prerequisites

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

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

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

  1. Open the API Library は Google API Consoleにあります。
  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. [認証情報を作成] > [OAuth クライアント ID] をクリックします。
  3. アプリケーションの種類として [テレビと制限付き入力デバイス] を選択します。
  4. OAuth 2.0 クライアントに名前を付け、[作成] をクリックします。

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

スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストでき、ユーザーはアプリケーションに付与するアクセス権をコントロールできます。したがって、リクエストされたスコープの数とユーザーの同意を取得する可能性の間には、逆関係が存在する場合があります。

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

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

OAuth 2.0 アクセス トークンの取得

入力機能が制限されたデバイス上でアプリが実行されている場合でも、ユーザーは、入力フローが豊富なデバイスに対する個別のアクセス権を持って、この承認フローを完了する必要があります。 フローの流れは次のとおりです。

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

以下の図に、このプロセスを示します。

ユーザーが、ブラウザがある別のデバイスにログインした場合

以降のセクションでは、これらのステップについて詳しく説明します。デバイスで利用できる機能およびランタイム環境の範囲を考えると、このドキュメントの例では、curl コマンドライン ユーティリティを使用します。これらの例は、さまざまな言語やランタイムに簡単に移植できるはずです。

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

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

パラメータ
client_id 必須

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

scope 必須

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

スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストでき、ユーザーはアプリケーションに付与するアクセス権の量を制御できます。したがって、リクエストされたスコープの数とユーザーの同意を得る可能性の間には、逆関係があります。

Examples

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

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

client_id=client_id&scope=

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

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

ステップ 2: 認証サーバーの応答を処理する

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

成功のレスポンス

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

Properties
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 サイズの文字を処理できるフィールドに表示する必要があります。つまり、コード 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。この値は、 API ConsoleCredentials pageにあります。
client_secret 指定された client_id のクライアント シークレット。この値は、 API ConsoleCredentials pageにあります。
device_code ステップ 2 で認証サーバーから返された device_code
grant_type urn:ietf:params:oauth:grant-type:device_code に設定します。

Examples

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

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" \
         /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"
}

その他のエラー

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

エラー HTTP ステータス コード Description
invalid_client 401 OAuth クライアントが見つかりませんでした。たとえば、client_id パラメータ値が無効な場合に発生します。
invalid_grant 400 code パラメータ値が無効です。
unsupported_grant_type 400 grant_type パラメータ値が無効です。

Google API の呼び出し

アプリケーションでアクセス トークンを取得した後、その 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

アクセス トークンの更新

アクセス トークンは定期的に期限切れになり、関連する 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",
  "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