このドキュメントでは、JavaScript ウェブ アプリケーションから YouTube Data API にアクセスするための OAuth 2.0 認証を実装する方法について説明します。OAuth 2.0 では、ユーザー名やパスワードなどの情報を秘密にしたまま、ユーザーが特定のデータをアプリケーションと共有できます。たとえば、アプリケーションで OAuth 2.0 を使用して、チャンネルの YouTube データを取得する権限を取得できます。
この OAuth 2.0 フローは、暗黙的グラント フローと呼ばれます。これは、ユーザーがアプリケーションにいる間のみ API にアクセスするアプリケーション向けに設計されています。これらのアプリケーションは機密情報を保存できません。
このフローでは、アプリはクエリ パラメータを使用してアプリとアプリに必要な API アクセスの種類を識別する Google URL を開きます。URL は現在のブラウザ ウィンドウまたはダイアログで開くことができます。ユーザーは Google で認証し、リクエストされた権限を付与できます。Google はユーザーをアプリにリダイレクトします。リダイレクトにはアクセス トークンが含まれており、アプリはこのトークンを検証してから API リクエストを行います。
Google API クライアント ライブラリと Google Identity Services
JavaScript 用 Google API クライアント ライブラリを使用して Google に承認済み呼び出しを行う場合は、Google Identity Services JavaScript ライブラリを使用して承認フローを処理する必要があります。より安全な PKCE を使用した認可コードフローに基づく Google Identity Services のコードモデルを使用することを強くおすすめします。
前提条件
プロジェクトでAPI を有効にする
Google API を呼び出すアプリケーションは、API Console でそれらの API を有効にする必要があります。
プロジェクトで API を有効にするには:
- Google API Console で API ライブラリを開きます。
- プロンプトが表示されたら、プロジェクトのいずれかを選択するか、新しいプロジェクトを作成します。
- [ライブラリ] ページで、YouTube Data API を見つけて有効にします。アプリケーションで使用する他の API を見つけて、それらも有効にします。
承認認証情報を作成する
OAuth 2.0 を使用して Google API にアクセスするアプリケーションは、Google の OAuth 2.0 サーバーに対して自身の身元を示す認証情報を持つ必要があります。次の手順では、プロジェクトの認証情報を作成する方法について説明します。アプリケーションは、この認証情報を使用して、そのプロジェクトで有効にした API にアクセスできます。
- [クライアント] ページに移動します。
- [クライアントを作成] をクリックします。
- アプリケーションの種類として [ウェブ アプリケーション] を選択します。
- フォームに入力します。JavaScript を使用して承認済みの Google API リクエストを行うアプリケーションは、承認済みの JavaScript 生成元を指定する必要があります。オリジンは、アプリケーションが OAuth 2.0 サーバーにリクエストを送信できるドメインを識別します。これらのオリジンは、Google の検証ルールに準拠する必要があります。
アクセス スコープを特定する
スコープを指定すると、アプリケーションからのアクセス要求は必要なリソースのみに限定されるようになり、ユーザーはアプリケーションに付与するアクセスレベルを制御できます。したがって、リクエストされるスコープの数とユーザーの同意を得られる可能性の間には、逆相関がある可能性があります。
OAuth 2.0 認証の実装を開始する前に、アプリがアクセス権限を必要とするスコープを設定しておくことをおすすめします。
YouTube Data API v3 では、次のスコープが使用されます。
| 範囲 | 説明 |
|---|---|
https://www. |
YouTube アカウントの管理 |
https://www. |
現在アクティブなチャンネル メンバー、メンバーの現在のレベル、いつメンバーになったかをリストで確認できます。 |
https://www. |
YouTube 動画、評価、コメント、字幕の表示、編集、完全削除 |
https://www. |
YouTube アカウントの表示 |
https://www. |
YouTube 動画の管理 |
https://www. |
YouTube のアセットや関連するコンテンツの表示と管理 |
https://www. |
YouTube パートナーの監査プロセス時に関連する YouTube チャンネルの個人情報の表示 |
OAuth 2.0 API スコープのドキュメントには、Google API へのアクセスに使用できるスコープの完全なリストが記載されています。
OAuth 2.0 アクセス トークンを取得する
次の手順は、アプリケーションが Google の OAuth 2.0 サーバーと連携して、ユーザーに代わって API リクエストを実行するためのユーザーの同意を得る方法を示しています。ユーザーの承認が必要な Google API リクエストを実行するには、アプリがその同意を得ている必要があります。
ステップ 1: Google の OAuth 2.0 サーバーにリダイレクトする
ユーザーのデータにアクセスする権限をリクエストするには、ユーザーを Google の OAuth 2.0 サーバーにリダイレクトします。
OAuth 2.0 エンドポイント
https://accounts.google.com/o/oauth2/v2/auth の Google の OAuth 2.0 エンドポイントからアクセスをリクエストする URL を生成します。このエンドポイントには HTTPS 経由でアクセスできます。プレーン HTTP 接続は拒否されます。
Google 認可サーバーは、ウェブ サーバー アプリケーションに対して次のクエリ文字列パラメータをサポートしています。
| パラメータ | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
client_id |
必須
アプリケーションのクライアント ID。この値は、Cloud Console の [クライアント] ページで確認できます。 |
||||||||||||||||
redirect_uri |
必須
ユーザーが認可フローを完了した後に API サーバーがユーザーをリダイレクトする場所を指定します。この値は、クライアントの Google Cloud コンソールのクライアント ページで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI のいずれかと完全に一致する必要があります。この値が、指定された
|
||||||||||||||||
response_type |
必須
JavaScript アプリケーションでは、パラメータの値を |
||||||||||||||||
scope |
必須
アプリケーションがユーザーの代わりにアクセスできるリソースを識別するスコープのスペース区切りリスト。これらの値は、Google がユーザーに表示する同意画面に反映されます。 スコープを指定すると、アプリケーションからのアクセス要求は必要なリソースのみに限定されるようになり、ユーザーはアプリケーションに付与するアクセスレベルを制御できます。したがって、リクエストされるスコープの数とユーザーの同意が得られる可能性の間には逆相関があります。 YouTube Data API v3 では、次のスコープが使用されます。
OAuth 2.0 API スコープのドキュメントには、Google API へのアクセスに使用できるスコープの完全なリストが記載されています。 可能な限り、コンテキストで認可スコープへのアクセスをリクエストすることをおすすめします。段階的認証を使用して、ユーザーデータへのアクセス権限を状況に合わせてリクエストすることで、ユーザーはアプリケーションがリクエストしているアクセス権限を必要とする理由を理解できます。 |
||||||||||||||||
state |
推奨
認可リクエストと認可サーバーのレスポンスの間で状態を維持するためにアプリケーションが使用する文字列値を指定します。ユーザーがアプリのアクセス リクエストを承認または拒否すると、サーバーは このパラメータは、ユーザーをアプリケーション内の正しいリソースに誘導する、ノンスを送信する、クロスサイト リクエスト フォージェリを軽減するなど、さまざまな目的で使用できます。 |
||||||||||||||||
include_granted_scopes |
省略可
アプリケーションが段階的認可を使用して、状況に応じて追加のスコープへのアクセスをリクエストできるようにします。このパラメータの値を |
||||||||||||||||
enable_granular_consent |
省略可
デフォルトは Google がアプリのきめ細かい権限を有効にすると、このパラメータは無効になります。 |
||||||||||||||||
login_hint |
省略可
アプリが認証を試みているユーザーを把握している場合は、このパラメータを使用して Google 認証サーバーにヒントを提供できます。サーバーは、ログイン フォームのメール フィールドを事前入力するか、適切なマルチログイン セッションを選択することで、ヒントを使用してログイン フローを簡素化します。 パラメータ値をメールアドレスまたは |
||||||||||||||||
prompt |
省略可
ユーザーに表示するプロンプトのスペース区切りの大文字と小文字を区別するリスト。このパラメータを指定しない場合、ユーザーにプロンプトが表示されるのは、プロジェクトがアクセスをリクエストした最初の 1 回のみです。詳しくは、 再同意を求めるをご覧ください。 次の値があります。
|
||||||||||||||||
Google の認証サーバーへのリダイレクトの例
読みやすくするため、改行とスペースを挿入した URL の例を以下に示します。この URL は、ユーザーの YouTube データを取得するためのアクセスを許可するスコープへのアクセスをリクエストします。増分認証(include_granted_scopes=true)を使用して、新しいアクセス トークンが、ユーザーが以前にアプリケーションにアクセスを許可したすべてのスコープをカバーするようにします。この例では、他のいくつかのパラメータも設定されています。
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl& include_granted_scopes=true& response_type=token& state=state_parameter_passthrough_value& redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback& client_id=client_id
リクエスト URL を作成したら、ユーザーをその URL にリダイレクトします。
JavaScript サンプルコード
次の JavaScript スニペットは、JavaScript 用 Google APIs クライアント ライブラリを使用せずに JavaScript で認証フローを開始する方法を示しています。この OAuth 2.0 エンドポイントはクロスオリジン リソース シェアリング(CORS)をサポートしていないため、このスニペットは、そのエンドポイントへのリクエストを開くフォームを作成します。
/* * Create form to request access token from Google's OAuth 2.0 server. */ function oauthSignIn() { // Google's OAuth 2.0 endpoint for requesting an access token var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth'; // Create <form> element to submit parameters to OAuth 2.0 endpoint. var form = document.createElement('form'); form.setAttribute('method', 'GET'); // Send as a GET request. form.setAttribute('action', oauth2Endpoint); // Parameters to pass to OAuth 2.0 endpoint. var params = {'client_id': 'YOUR_CLIENT_ID', 'redirect_uri': 'YOUR_REDIRECT_URI', 'response_type': 'token', 'scope': 'https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly', 'include_granted_scopes': 'true', 'state': 'pass-through value'}; // Add form parameters as hidden input values. for (var p in params) { var input = document.createElement('input'); input.setAttribute('type', 'hidden'); input.setAttribute('name', p); input.setAttribute('value', params[p]); form.appendChild(input); } // Add form to page and submit it to open the OAuth 2.0 endpoint. document.body.appendChild(form); form.submit(); }
ステップ 2: Google がユーザーに同意を求める
このステップで、ユーザーはリクエストされたアクセス権をアプリに付与するかどうかを決定します。この段階で、Google は同意ウィンドウを表示します。このウィンドウには、アプリケーションの名前と、ユーザーの認証情報を使用してアクセス権限をリクエストしている Google API サービス、付与されるアクセス スコープの概要が表示されます。ユーザーは、アプリケーションがリクエストした 1 つ以上のスコープへのアクセス権の付与を同意するか、リクエストを拒否できます。
この段階では、アプリケーションは Google の OAuth 2.0 サーバーからのレスポンスを待機するだけで、何もする必要はありません。レスポンスには、アクセスが許可されたかどうかが示されます。このレスポンスについては、次のステップで説明します。
エラー
Google の OAuth 2.0 認可エンドポイントへのリクエストで、想定される認証フローと認可フローではなく、ユーザー向けのエラー メッセージが表示されることがあります。一般的なエラーコードと推奨される解決策は次のとおりです。
admin_policy_enforced
Google アカウントの Google Workspace 管理者のポリシーにより、リクエストされた 1 つ以上のスコープを承認できません。管理者が OAuth クライアント ID に明示的にアクセス権を付与するまで、すべてのスコープまたは機密性の高い制限付きスコープへのアクセスを制限する方法について詳しくは、Google Workspace 管理者向けヘルプ記事の Google Workspace のデータにアクセスできるサードパーティ製アプリと内部アプリを制御するをご覧ください。
disallowed_useragent
認可エンドポイントは、Google の OAuth 2.0 ポリシーで禁止されている埋め込みユーザー エージェント内に表示されます。
iOS と macOS のデベロッパーは、WKWebView で承認リクエストを開くときにこのエラーが発生することがあります。代わりに、デベロッパーは Google ログイン for iOS や OpenID Foundation の AppAuth for iOS などの iOS ライブラリを使用する必要があります。
ウェブ デベロッパーは、iOS または macOS アプリが埋め込みユーザー エージェントで一般的なウェブリンクを開き、ユーザーがサイトから Google の OAuth 2.0 認可エンドポイントに移動したときに、このエラーに遭遇する可能性があります。デベロッパーは、ユニバーサル リンク ハンドラまたはデフォルトのブラウザアプリを含む、オペレーティング システムのデフォルトのリンク ハンドラで一般的なリンクを開けるようにする必要があります。SFSafariViewController ライブラリもサポートされているオプションです。
org_internal
リクエストの OAuth クライアント ID は、特定の Google Cloud 組織内の Google アカウントへのアクセスを制限するプロジェクトの一部です。この構成オプションの詳細については、OAuth 同意画面の設定に関するヘルプ記事のユーザータイプのセクションをご覧ください。
invalid_client
リクエストの送信元がこのクライアントに対して承認されていません。origin_mismatch をご覧ください。
deleted_client
リクエストの作成に使用されている OAuth クライアントが削除されました。削除は、手動で行うことも、未使用のクライアント の場合は自動で行うこともできます。削除したクライアントは、削除後 30 日以内であれば復元できます。詳細
invalid_grant
増分認可を使用している場合、トークンの有効期限が切れているか、無効になっている可能性があります。ユーザーを再度認証し、新しいトークンを取得するためのユーザーの同意を求めます。このエラーが引き続き表示される場合は、アプリケーションが正しく構成されていること、リクエストで正しいトークンとパラメータを使用していることを確認してください。それ以外の場合は、ユーザー アカウントが削除または無効になっている可能性があります。
origin_mismatch
承認リクエストを開始した JavaScript のスキーム、ドメイン、ポートが、OAuth クライアント ID に登録されている承認済みの JavaScript 生成元 URI と一致していない可能性があります。Google Cloud コンソール の [クライアント] ページで、承認済みの JavaScript 生成元を確認します。
redirect_uri_mismatch
認可リクエストで渡された redirect_uri が、OAuth クライアント ID の承認済みリダイレクト URI と一致しません。Google Cloud コンソールの [クライアント] ページで、承認済みリダイレクト URI を確認します。
承認リクエストを開始した JavaScript のスキーム、ドメイン、ポートが、OAuth クライアント ID に登録されている承認済みの JavaScript 生成元 URI と一致していない可能性があります。Google Cloud コンソール のクライアント ページで、承認済みの JavaScript 生成元を確認します。
redirect_uri パラメータは、非推奨となりサポートが終了した OAuth 帯域外(OOB)フローを参照している可能性があります。統合を更新するには、移行ガイドを参照してください。
invalid_request
リクエストに問題がありました。これには、次のような理由が考えられます。
- リクエストの形式が正しくありませんでした
- リクエストに必須パラメータが含まれていませんでした
- リクエストで、Google がサポートしていない認証方法が使用されています。OAuth 統合で推奨される統合方法が使用されていることを確認する
ステップ 3: OAuth 2.0 サーバーのレスポンスを処理する
OAuth 2.0 エンドポイント
OAuth 2.0 サーバーは、アクセス トークン リクエストで指定された redirect_uri にレスポンスを送信します。
ユーザーがリクエストを承認すると、レスポンスにアクセス トークンが格納されます。ユーザーがリクエストを承認しないと、レスポンスにエラー メッセージが格納されます。アクセス トークンまたはエラー メッセージは、次の例に示すように、リダイレクト URI のハッシュ フラグメントで返されます。
アクセス トークンのレスポンス:
https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600
フラグメント文字列には、
access_tokenパラメータに加えて、常にBearerに設定されるtoken_typeパラメータと、トークンの有効期間を秒単位で指定するexpires_inパラメータも含まれます。アクセス トークン リクエストでstateパラメータが指定されている場合、その値もレスポンスに含まれます。- エラー レスポンス:
https://oauth2.example.com/callback#error=access_denied
OAuth 2.0 サーバー レスポンスの例
このフローをテストするには、次のサンプル URL をクリックします。この URL は、Google ドライブのファイルのメタデータを表示するための読み取り専用アクセスと、Google カレンダーの予定を表示するための読み取り専用アクセスをリクエストします。
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube.force-ssl& include_granted_scopes=true& response_type=token& state=state_parameter_passthrough_value& redirect_uri=http%3A%2F%2Flocalhost%2Foauth2callback& client_id=client_id
OAuth 2.0 フローが完了すると、ブラウザは OAuth フローをテストするためのツールである OAuth 2.0 プレイグラウンドにリダイレクトされます。OAuth 2.0 Playground で認証コードが自動的に取得されていることがわかります。
ステップ 4: ユーザーが許可したスコープを確認する
複数の権限(スコープ)をリクエストした場合、ユーザーがアプリにすべての権限へのアクセスを許可するとは限りません。アプリは、実際に付与されたスコープを確認し、一部の権限が拒否された状況に適切に対応する必要があります。通常は、拒否されたスコープに依存する機能を無効にします。
ただし、例外もあります。ドメイン全体の権限の委任が設定されている Google Workspace Enterprise アプリ、または [信頼できる] とマークされているアプリは、詳細な権限の同意画面を省略します。これらのアプリでは、ユーザーにきめ細かい権限の同意画面は表示されません。代わりに、アプリはリクエストされたすべてのスコープを受け取るか、1 つも受け取らないかのどちらかになります。
詳しくは、きめ細かい権限を処理する方法をご覧ください。
OAuth 2.0 エンドポイント
ユーザーが特定のスコープへのアクセス権をアプリケーションに付与しているかどうかを確認するには、アクセス トークン レスポンスの scope フィールドを調べます。access_token によって付与されたアクセス権のスコープ。スペース区切りの大文字と小文字が区別される文字列のリストとして表されます。
たとえば、次のサンプル アクセス トークン レスポンスは、ユーザーが読み取り専用のドライブ アクティビティとカレンダーの予定の権限をアプリに付与したことを示しています。
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
Google API の呼び出し
OAuth 2.0 エンドポイント
アプリケーションがアクセス トークンを取得した後、API で必要なアクセス スコープが付与されている場合は、トークンを使用して特定のユーザー アカウントの代わりに Google API を呼び出すことができます。これを行うには、access_token クエリ パラメータまたは Authorization HTTP ヘッダー Bearer 値のいずれかを含めることで、API へのリクエストにアクセス トークンを含めます。クエリ文字列はサーバーログに表示される傾向があるため、可能な場合は HTTP ヘッダーを使用することをおすすめします。ほとんどの場合、クライアント ライブラリを使用して Google API への呼び出しを設定できます(たとえば、YouTube ライブ ストリーミング API を呼び出す場合など)。
YouTube Live Streaming API はサービス アカウント フローをサポートしていません。サービス アカウントを YouTube アカウントにリンクする方法がないため、このフローでリクエストを承認しようとすると、NoLinkedYouTubeAccount エラーが生成されます。
OAuth 2.0 Playground では、すべての Google API を試して、そのスコープを確認できます。
HTTP GET の例
Authorization: Bearer HTTP ヘッダーを使用した
liveBroadcasts.list エンドポイント(YouTube Live Streaming API)への呼び出しは、次のようになります。独自のアクセス トークンを指定する必要があります。
GET /youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
以下は、access_token クエリ文字列パラメータを使用して認証済みユーザーに対して同じ API を呼び出す例です。
GET https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true
curl の例
これらのコマンドは、curl コマンドライン アプリケーションでテストできます。HTTP ヘッダー オプション(推奨)を使用する例を次に示します。
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id%2Csnippet&mine=true
または、クエリ文字列パラメータ オプションを使用します。
curl https://www.googleapis.com/youtube/v3/liveBroadcasts?access_token=access_token&part=id%2Csnippet&mine=true
JavaScript サンプルコード
次のコード スニペットは、CORS(クロスオリジン リソース シェアリング)を使用して Google API にリクエストを送信する方法を示しています。この例では、JavaScript 用 Google API クライアント ライブラリを使用していません。ただし、クライアント ライブラリを使用していない場合でも、そのライブラリのドキュメントにある CORS サポートのガイドは、これらのリクエストをより深く理解するのに役立つ可能性があります。
このコード スニペットでは、access_token 変数は、承認済みユーザーに代わって API リクエストを行うために取得したトークンを表します。完全な例では、そのトークンをブラウザのローカル ストレージに保存し、API リクエストを行うときに取得する方法を示します。
var xhr = new XMLHttpRequest(); xhr.open('GET', 'https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id,snippet&mine=true' + 'access_token=' + params['access_token']); xhr.onreadystatechange = function (e) { console.log(xhr.response); }; xhr.send(null);
サンプルコードの全文
OAuth 2.0 エンドポイント
このコードサンプルは、JavaScript 用 Google API クライアント ライブラリを使用せずに JavaScript で OAuth 2.0 フローを完了する方法を示しています。このコードは、API リクエストを試すためのボタンを表示する HTML ページ用です。ボタンをクリックすると、ページがブラウザのローカル ストレージに API アクセス トークンを保存しているかどうかがコードによって確認されます。条件を満たしている場合は、API リクエストを実行します。それ以外の場合は、OAuth 2.0 フローを開始します。
OAuth 2.0 フローの場合、ページは次の手順を行います。
- ユーザーを Google の OAuth 2.0 サーバーにリダイレクトし、
https://www.googleapis.com/auth/youtube.force-sslスコープとhttps://www.googleapis.com/auth/calendar.readonlyスコープへのアクセスをリクエストします。 - 1 つ以上のリクエストされたスコープへのアクセスを許可(または拒否)すると、ユーザーは元のページにリダイレクトされます。元のページでは、フラグメント識別子文字列からアクセス トークンが解析されます。
- このページでは、ユーザーがアプリケーションにアクセス権を付与したスコープを確認できます。
ユーザーがリクエストされた scope() へのアクセスを許可している場合、ページはアクセス トークンを使用してサンプル API リクエストを行います。
この API リクエストは、YouTube Data API の
liveBroadcasts.listメソッドを呼び出して、承認済みユーザーの YouTube チャンネルの動画ブロードキャストのリストを取得します。- リクエストが正常に実行されると、API レスポンスがブラウザのデバッグ コンソールに記録されます。
Google アカウントの [権限] ページで、アプリへのアクセスを取り消すことができます。アプリは、クライアント ID の作成時に OAuth 同意画面内のブランディング ページで指定されたアプリケーション名として表示されます。
このコードをローカルで実行するには、認証情報に対応する YOUR_CLIENT_ID 変数と YOUR_REDIRECT_URI 変数の値を設定する必要があります。YOUR_REDIRECT_URI 変数は、ページが配信されている URL と同じ URL に設定する必要があります。この値は、Cloud コンソールの [クライアント] ページで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI のいずれかと完全に一致する必要があります。この値が承認済みの URI と一致しない場合、redirect_uri_mismatch エラーが発生します。また、プロジェクトでこのリクエストの適切な API を有効にする必要があります。
<html><head></head><body>
<script>
var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
// Parse query string to see if page request is coming from OAuth 2.0 server.
var fragmentString = location.hash.substring(1);
var params = {};
var regex = /([^&=]+)=([^&]*)/g, m;
while (m = regex.exec(fragmentString)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
if (Object.keys(params).length > 0 && params['state']) {
if (params['state'] == localStorage.getItem('state')) {
localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
trySampleRequest();
} else {
console.log('State mismatch. Possible CSRF attack');
}
}
// Function to generate a random state value
function generateCryptoRandomState() {
const randomValues = new Uint32Array(2);
window.crypto.getRandomValues(randomValues);
// Encode as UTF-8
const utf8Encoder = new TextEncoder();
const utf8Array = utf8Encoder.encode(
String.fromCharCode.apply(null, randomValues)
);
// Base64 encode the UTF-8 data
return btoa(String.fromCharCode.apply(null, utf8Array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
}
// If there's an access token, try an API request.
// Otherwise, start OAuth 2.0 flow.
function trySampleRequest() {
var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
if (params && params['access_token']) {
// User authorized the request. Now, check which scopes were granted.
if (params['scope'].includes('https://www.googleapis.com/auth/drive.metadata.readonly')) {
// User authorized read-only Drive activity permission.
// Calling the APIs, etc.
var xhr = new XMLHttpRequest();
xhr.open('GET',
'https://www.googleapis.com/youtube/v3/liveBroadcasts?part=id,snippet&mine=true' +
'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response);
} else if (xhr.readyState === 4 && xhr.status === 401) {
// Token invalid, so prompt for user permission.
oauth2SignIn();
}
};
xhr.send(null);
}
else {
// User didn't authorize read-only Drive activity permission.
// Update UX and application accordingly
console.log('User did not authorize read-only Drive activity permission.');
}
// Check if user authorized Calendar read permission.
if (params['scope'].includes('https://www.googleapis.com/auth/calendar.readonly')) {
// User authorized Calendar read permission.
// Calling the APIs, etc.
console.log('User authorized Calendar read permission.');
}
else {
// User didn't authorize Calendar read permission.
// Update UX and application accordingly
console.log('User did not authorize Calendar read permission.');
}
} else {
oauth2SignIn();
}
}
/*
* Create form to request access token from Google's OAuth 2.0 server.
*/
function oauth2SignIn() {
// create random state value and store in local storage
var state = generateCryptoRandomState();
localStorage.setItem('state', state);
// Google's OAuth 2.0 endpoint for requesting an access token
var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
// Create element to open OAuth 2.0 endpoint in new window.
var form = document.createElement('form');
form.setAttribute('method', 'GET'); // Send as a GET request.
form.setAttribute('action', oauth2Endpoint);
// Parameters to pass to OAuth 2.0 endpoint.
var params = {'client_id': YOUR_CLIENT_ID,
'redirect_uri': YOUR_REDIRECT_URI,
'scope': 'https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/calendar.readonly',
'state': state,
'include_granted_scopes': 'true',
'response_type': 'token'};
// Add form parameters as hidden input values.
for (var p in params) {
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', p);
input.setAttribute('value', params[p]);
form.appendChild(input);
}
// Add form to page and submit it to open the OAuth 2.0 endpoint.
document.body.appendChild(form);
form.submit();
}
</script>
<button onclick="trySampleRequest();">Try sample request</button>
</body></html>JavaScript 生成元検証ルール
Google は、デベロッパーがアプリケーションの安全性を維持できるように、JavaScript のオリジンに次の検証ルールを適用します。JavaScript の生成元は、次のルールに準拠している必要があります。これらのルールで使用されるドメイン、ホスト、スキームの定義については、RFC 3986 セクション 3 をご覧ください。
| 検証規則 | |
|---|---|
| スキーム |
JavaScript のオリジンでは、プレーン HTTP ではなく HTTPS スキームを使用する必要があります。ローカルホスト URI(ローカルホスト IP アドレス URI を含む)は、このルールの対象外です。 |
| ホスト |
ホストに未加工の IP アドレスを指定することはできません。ローカルホストの IP アドレスはこのルールの対象外です。 |
| ドメイン |
“googleusercontent.com” にすることはできません。goo.gl など)を含めることはできません。 |
| Userinfo |
JavaScript のオリジンに userinfo サブコンポーネントを含めることはできません。 |
| [パス] |
JavaScript のオリジンにパス コンポーネントを含めることはできません。 |
| クエリ |
JavaScript のオリジンにクエリ コンポーネントを含めることはできません。 |
| Fragment |
JavaScript のオリジンにフラグメント コンポーネントを含めることはできません。 |
| 文字数 |
JavaScript 生成元には、次の文字を含めることはできません。
|
段階的な認可
OAuth 2.0 プロトコルでは、アプリはリソースへのアクセス権限をリクエストします。リソースはスコープによって識別されます。リソースの承認は、必要なときにリクエストすることがユーザー エクスペリエンスのベスト プラクティスとされています。この方法を有効にするため、Google の認可サーバーは段階的な認可をサポートしています。この機能を使用すると、必要なときにスコープをリクエストできます。ユーザーが新しいスコープの権限を付与すると、ユーザーがプロジェクトに付与したすべてのスコープを含むトークンと交換できる認証コードが返されます。
たとえば、アプリが認証済みユーザーの YouTube チャンネルのデータを取得し、特別なフローを通じてユーザーが YouTube アナリティクス データを取得できるようにするとします。この場合、ログイン時にアプリが https://www.googleapis.com/auth/youtube.force-ssl スコープへのアクセスのみをリクエストすることがあります。ただし、ユーザーが自分のチャンネルのアナリティクス データにアクセスしようとした場合、アプリは https://www.googleapis.com/auth/yt-analytics.readonly スコープへのアクセスもリクエストできます。
増分認可で取得したアクセス トークンには、次のルールが適用されます。
- このトークンを使用して、新しい統合認証にロールアップされたスコープに対応するリソースにアクセスできます。
- 結合された承認の更新トークンを使用してアクセス トークンを取得すると、アクセス トークンは結合された承認を表し、レスポンスに含まれる
scope値のいずれにも使用できます。 - 統合された承認には、ユーザーが API プロジェクトに付与したすべてのスコープが含まれます。付与が異なるクライアントからリクエストされた場合でも同様です。たとえば、ユーザーがアプリケーションのデスクトップ クライアントを使用して 1 つのスコープへのアクセスを許可し、モバイル クライアントを使用して同じアプリケーションに別のスコープを許可した場合、結合された認可には両方のスコープが含まれます。
- 結合された認可を表すトークンを取り消すと、関連付けられたユーザーに代わって、その認可のすべてのスコープへのアクセスが同時に取り消されます。
次のコードサンプルは、既存のアクセス トークンにスコープを追加する方法を示しています。このアプローチにより、アプリは複数のアクセス トークンを管理する必要がなくなります。
OAuth 2.0 エンドポイント
この例では、呼び出し元のアプリは、ユーザーがすでにアプリに付与しているアクセス権に加えて、ユーザーの YouTube データを取得するためのアクセス権をリクエストしています。
既存のアクセス トークンにスコープを追加するには、Google の OAuth 2.0 サーバーへのリクエストに include_granted_scopes パラメータを含めます。
次のコード スニペットは、その方法を示しています。このスニペットは、アクセス トークンが有効なスコープをブラウザのローカル ストレージに保存していることを前提としています。(完全なサンプルコードでは、ブラウザのローカル ストレージで oauth2-test-params.scope プロパティを設定して、アクセス トークンが有効なスコープのリストを保存します)。
このスニペットは、アクセス トークンが有効なスコープと、特定のクエリで使用するスコープを比較します。アクセス トークンがそのスコープをカバーしていない場合、OAuth 2.0 フローが開始されます。ここで、oauth2SignIn 関数は、ステップ 2 で提供された関数と同じです(後で完全な例で提供されます)。
var SCOPE = 'https://www.googleapis.com/auth/youtube.force-ssl'; var params = JSON.parse(localStorage.getItem('oauth2-test-params')); var current_scope_granted = false; if (params.hasOwnProperty('scope')) { var scopes = params['scope'].split(' '); for (var s = 0; s < scopes.length; s++) { if (SCOPE == scopes[s]) { current_scope_granted = true; } } } if (!current_scope_granted) { oauth2SignIn(); // This function is defined elsewhere in this document. } else { // Since you already have access, you can proceed with the API request. }
トークンの取り消し
ユーザーがアプリに付与したアクセス権を取り消したい場合もあります。ユーザーは、 アカウント設定にアクセスしてアクセス権を取り消すことができます。詳しくは、アカウントにアクセスできるサードパーティのサイトやアプリのサポート ドキュメントの「サイトやアプリのアクセス権を削除する」セクションをご覧ください。
アプリケーションが、自身に付与されたアクセス権をプログラムで取り消すことも可能です。ユーザーが登録を解除した場合、アプリを削除した場合、アプリに必要な API リソースが大幅に変更された場合などには、プログラムによる取り消しが重要になります。つまり、削除プロセスの一部として、以前にアプリに付与された権限が削除されるように API リクエストを含めることができます。
OAuth 2.0 エンドポイント
プログラムでトークンを取り消すには、アプリケーションが 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 が返されます。
次の JavaScript スニペットは、JavaScript 用 Google API クライアント ライブラリを使用せずに JavaScript でトークンを取り消す方法を示しています。トークンを取り消すための Google の OAuth 2.0 エンドポイントはクロスオリジン リソース シェアリング(CORS)をサポートしていないため、コードは XMLHttpRequest() メソッドを使用してリクエストを投稿するのではなく、フォームを作成してエンドポイントに送信します。
function revokeAccess(accessToken) { // Google's OAuth 2.0 endpoint for revoking access tokens. var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke'; // Create <form> element to use to POST data to the OAuth 2.0 endpoint. var form = document.createElement('form'); form.setAttribute('method', 'post'); form.setAttribute('action', revokeTokenEndpoint); // Add access token to the form so it is set as value of 'token' parameter. // This corresponds to the sample curl request, where the URL is: // https://oauth2.googleapis.com/revoke?token={token} var tokenField = document.createElement('input'); tokenField.setAttribute('type', 'hidden'); tokenField.setAttribute('name', 'token'); tokenField.setAttribute('value', accessToken); form.appendChild(tokenField); // Add form to page and submit it to actually revoke the token. document.body.appendChild(form); form.submit(); }
クロスアカウント保護機能の実装
ユーザーのアカウントを保護するために行うべき追加の手順として、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
クロスアカウント保護の実装方法と利用可能なイベントの完全なリストについては、 クロスアカウント保護機能でユーザー アカウントを保護する をご覧ください。