このドキュメントでは、JavaScript ウェブ アプリケーションから Google API にアクセスするための OAuth 2.0 認可を実装する方法について説明します。OAuth 2.0 では、ユーザー名やパスワードなどの情報を秘密にしたまま、ユーザーが特定のデータをアプリケーションと共有できます。たとえば、アプリケーションは OAuth 2.0 を使用して、Google ドライブにファイルを保存する権限をユーザーから取得できます。
この 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 ライブラリを開きます。
- プロンプトが表示されたら、プロジェクトのいずれかを選択するか、新しいプロジェクトを作成します。
- API ライブラリには、利用可能なすべての API がプロダクト ファミリーと人気度に応じてグループ化されて表示されます。有効にする API がリストで見当たらない場合は、検索して見つけるか、その API が属するプロダクト ファミリーの [すべて表示] をクリックします。
- 有効にする API を選択し、[有効にする] ボタンをクリックします。
- プロンプトが表示されたら、請求機能を有効にします。
- プロンプトが表示されたら、API の利用規約を確認し、同意します。
承認認証情報を作成する
OAuth 2.0 を使用して Google API にアクセスするアプリケーションには、Google の OAuth 2.0 サーバーにアプリケーションを識別させる認証情報が必要です。プロジェクトの認証情報を作成する手順は次のとおりです。アプリケーションは、認証情報を使用して、そのプロジェクトで有効にした API にアクセスできます。
- [クライアント] ページに移動します。
- [Create Client] をクリックします。
- アプリケーションの種類として [ウェブ アプリケーション] を選択します。
- フォームに入力します。JavaScript を使用して承認済みの Google API リクエストを行うアプリケーションでは、承認済みの JavaScript 生成元を指定する必要があります。オリジンは、アプリケーションが OAuth 2.0 サーバーにリクエストを送信できるドメインを識別します。これらのオリジンは、Google の検証ルールに準拠している必要があります。
アクセス スコープを特定する
スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストできます。また、ユーザーはアプリケーションに付与するアクセス量を制御できます。したがって、リクエストするスコープの数とユーザーの同意を得られる可能性は、反比例の関係にある可能性があります。
OAuth 2.0 認可の実装を開始する前に、アプリがアクセス許可を必要とするスコープを特定することをおすすめします。
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 コンソールの [クライアント] ページで確認できます。 |
||||||
redirect_uri |
必須
ユーザーが認可フローを完了した後に、API サーバーがユーザーをリダイレクトする場所を指定します。この値は、クライアントの Cloud コンソールのクライアント ページで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI のいずれかと完全に一致する必要があります。この値が、指定された
|
||||||
response_type |
必須
JavaScript アプリケーションでは、パラメータの値を |
||||||
scope |
必須
アプリケーションがユーザーに代わってアクセスできるリソースを識別するスコープのスペース区切りのリスト。これらの値は、Google がユーザーに表示する同意画面に反映されます。 スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストできます。また、ユーザーはアプリケーションに付与するアクセス量を制御できます。したがって、リクエストするスコープの数とユーザーの同意を得られる可能性は反比例の関係にあります。 アプリケーションでは、可能な限りコンテキスト内の認可スコープへのアクセスをリクエストすることをおすすめします。段階的な認可を使用して、状況に合わせてユーザーデータへのアクセスをリクエストすることで、アプリケーションがリクエストしているアクセスを必要とする理由をユーザーが理解しやすくなります。 |
||||||
state |
推奨
アプリケーションが認可リクエストと認可サーバーのレスポンスの間で状態を維持するために使用する任意の文字列値を指定します。サーバーは、ユーザーがアプリケーションのアクセス リクエストを承認または拒否した後、 このパラメータは、ユーザーをアプリケーション内の正しいリソースに誘導する、ノンスを送信する、クロスサイト リクエスト フォージェリを軽減するなど、いくつかの目的で使用できます。 |
||||||
include_granted_scopes |
省略可
アプリは、増分認証を使用して、コンテキスト内の追加スコープへのアクセスをリクエストできます。このパラメータの値を |
||||||
enable_granular_consent |
省略可
デフォルトは Google がアプリケーションの詳細な権限を有効にすると、このパラメータは無効になります。 |
||||||
login_hint |
省略可
アプリケーションが認証を試みるユーザーを把握している場合は、このパラメータを使用して Google 認証サーバーにヒントを提供できます。サーバーは、ログイン フォームのメール フィールドに事前入力するか、適切なマルチログイン セッションを選択することで、ログインフローを簡素化するためにヒントを使用します。 パラメータ値を、ユーザーの Google ID に相当するメールアドレスまたは |
||||||
prompt |
省略可
ユーザーに表示するプロンプトのスペース区切りのリスト(大文字と小文字を区別)。このパラメータを指定しない場合、ユーザーはプロジェクトがアクセスをリクエストした初回のみプロンプトが表示されます。詳しくは、 再同意を求めるをご覧ください。 次の値があります。
|
||||||
Google の認可サーバーへのリダイレクトの例
以下に URL の例を示します。読みやすくするために改行とスペースを入れています。
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& include_granted_scopes=true& response_type=token& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
リクエスト URL を作成したら、ユーザーをその URL にリダイレクトします。
JavaScript サンプルコード
次の JavaScript スニペットは、Google API クライアント ライブラリ for JavaScript を使用せずに 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/drive.metadata.readonly 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 Workspace 管理者のポリシーにより、Google アカウントはリクエストされた 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//www.googleapis.com/auth/drive.metadata.readonly%20https%3A//www.googleapis.com/auth/calendar.readonly& include_granted_scopes=true& response_type=token& state=state_parameter_passthrough_value& redirect_uri=https%3A//developers.google.com/oauthplayground& client_id=client_id
OAuth 2.0 フローが完了すると、ブラウザは OAuth フローをテストするためのツールである OAuth 2.0 Playground にリダイレクトされます。OAuth 2.0 Playground が認証コードを自動的に取得したことがわかります。
ステップ 4: ユーザーが付与したスコープを確認する
複数の権限(スコープ)をリクエストした場合、ユーザーがアプリにすべての権限へのアクセスを許可しないことがあります。アプリは、実際に付与されたスコープを確認し、一部の権限が拒否された状況を適切に処理する必要があります。通常は、拒否されたスコープに依存する機能を無効にします。
例外もございます。ドメイン全体の権限の委任が設定されている Google Workspace Enterprise アプリ、または信頼できるとしてマークされているアプリでは、詳細な権限の同意画面が省略されます。これらのアプリでは、詳細な権限の同意画面は表示されません。代わりに、アプリはリクエストされたすべてのスコープを受け取るか、まったく受け取らないかのいずれかになります。
詳細については、詳細な権限を処理する方法をご覧ください。
OAuth 2.0 エンドポイント
ユーザーが特定のスコープへのアクセスをアプリケーションに許可しているかどうかを確認するには、アクセス トークン レスポンスの scope フィールドを調べます。アクセス トークンによって付与されるアクセス スコープ。スペース区切りの大文字と小文字を区別する文字列のリストとして表されます。
たとえば、次のアクセス トークン レスポンスの例は、ユーザーがアプリケーションに読み取り専用のドライブ アクティビティとカレンダーの予定の権限へのアクセスを許可したことを示しています。
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/drive.metadata.readonly 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 への呼び出しを設定できます(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
JavaScript サンプルコード
以下のコード スニペットは、CORS(クロスオリジン リソース シェアリング)を使用して Google API にリクエストを送信する方法を示しています。この例では、JavaScript 用の Google API クライアント ライブラリを使用していません。ただし、クライアント ライブラリを使用していない場合でも、そのライブラリのドキュメントにある CORS サポート ガイドは、これらのリクエストをより深く理解するのに役立ちます。
このコード スニペットでは、access_token 変数は、承認されたユーザーに代わって API リクエストを行うために取得したトークンを表します。完全な例では、そのトークンをブラウザのローカル ストレージに保存し、API リクエストを行うときに取得する方法を示しています。
var xhr = new XMLHttpRequest(); xhr.open('GET', 'https://www.googleapis.com/drive/v3/about?fields=user&' + '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/drive.metadata.readonlyスコープとhttps://www.googleapis.com/auth/calendar.readonlyスコープへのアクセスをリクエストします。 - リクエストされた 1 つ以上のスコープへのアクセスを許可(または拒否)すると、ユーザーは元のページにリダイレクトされます。このページは、フラグメント識別子文字列からアクセス トークンを解析します。
- このページでは、ユーザーがアプリケーションにアクセスを許可したスコープを確認します。
ユーザーがリクエストされたスコープへのアクセスを許可している場合、ページはアクセス トークンを使用してサンプル API リクエストを行います。
API リクエストは、Drive API の
about.getメソッドを呼び出して、承認されたユーザーの Google ドライブ アカウントに関する情報を取得します。- リクエストが正常に実行されると、API レスポンスがブラウザのデバッグ コンソールに記録されます。
アプリへのアクセス権は、Google アカウントの [権限] ページで取り消すことができます。アプリは、クライアント ID の作成時に OAuth 同意画面のブランディング ページで指定したアプリケーション名として表示されます。
このコードをローカルで実行するには、認証情報に対応する YOUR_CLIENT_ID 変数と YOUR_REDIRECT_URI 変数の値を設定する必要があります。YOUR_REDIRECT_URI 変数は、ページが提供されている URL と同じ URL に設定する必要があります。この値は、Cloud Console の [クライアント] ページで構成した 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/drive/v3/about?fields=user&' +
'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/drive.metadata.readonly 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 スキームを使用する必要があります。localhost URI(localhost IP アドレス URI を含む)は、このルールの対象外です。 |
| ホスト |
ホストを未加工の IP アドレスにすることはできません。localhost の IP アドレスは、このルールの対象外です。 |
| ドメイン |
“googleusercontent.com” にすることはできません。goo.gl など)を含めることはできません。 |
| Userinfo |
JavaScript の生成元に userinfo サブコンポーネントを含めることはできません。 |
| [パス] |
JavaScript のオリジンにパス コンポーネントを含めることはできません。 |
| クエリ |
JavaScript のオリジンにクエリ コンポーネントを含めることはできません。 |
| Fragment |
JavaScript のオリジンにフラグメント コンポーネントを含めることはできません。 |
| 文字数 |
JavaScript 生成元には、次の文字を含めることはできません。
|
段階的な認可
OAuth 2.0 プロトコルでは、アプリはスコープによって識別されるリソースへのアクセス認可をリクエストします。ユーザー エクスペリエンスのベスト プラクティスとして、リソースの承認は必要なときにリクエストすることをおすすめします。この方法を可能にするため、Google の認可サーバーは段階的な認可をサポートしています。この機能を使用すると、必要に応じてスコープをリクエストできます。ユーザーが新しいスコープの権限を付与すると、ユーザーがプロジェクトに付与したすべてのスコープを含むトークンと交換できる認証コードが返されます。
たとえば、音楽トラックを試聴してミックスを作成できるアプリの場合、ログイン時に必要なリソースはごくわずかで、ログインするユーザーの名前だけで十分な場合があります。ただし、完成したミックスを保存するには、Google ドライブへのアクセスが必要になります。ほとんどのユーザーは、アプリが実際に必要としたときにのみ Google ドライブへのアクセスを求められるのが自然だと感じます。
この場合、アプリはログイン時に openid スコープと profile スコープをリクエストして基本的なログインを実行し、その後、ミックスを保存する最初のリクエスト時に https://www.googleapis.com/auth/drive.file スコープをリクエストします。
増分認可から取得したアクセス トークンには、次のルールが適用されます。
- このトークンは、新しい統合された認可に組み込まれたスコープに対応するリソースにアクセスするために使用できます。
- 結合された認可の更新トークンを使用してアクセス トークンを取得すると、アクセス トークンは結合された認可を表し、レスポンスに含まれる
scope値のいずれかに使用できます。 - 結合された認可には、ユーザーが API プロジェクトに付与したすべてのスコープが含まれます。これは、付与が異なるクライアントからリクエストされた場合でも同様です。たとえば、ユーザーがアプリケーションのデスクトップ クライアントを使用して 1 つのスコープへのアクセスを許可し、その後、モバイル クライアントを介して同じアプリケーションに別のスコープを許可した場合、結合された認可には両方のスコープが含まれます。
- 複合認証を表すトークンを取り消すと、関連付けられたユーザーに代わってその認証のすべてのスコープへのアクセス権が同時に取り消されます。
以下のコードサンプルは、既存のアクセス トークンにスコープを追加する方法を示しています。この方法により、アプリで複数のアクセス トークンを管理する必要がなくなります。
OAuth 2.0 エンドポイント
既存のアクセス トークンにスコープを追加するには、Google の OAuth 2.0 サーバーへのリクエストに include_granted_scopes パラメータを含めます。
次のコード スニペットは、その方法を示しています。このスニペットでは、アクセス トークンが有効なスコープがブラウザのローカル ストレージに保存されていることを前提としています。(実証済みの例 コードでは、ブラウザのローカル ストレージに oauth2-test-params.scope プロパティを設定することで、アクセス トークンが有効なスコープのリストを保存します)。
このスニペットは、アクセス トークンが有効なスコープと、特定のクエリに使用するスコープを比較します。アクセス トークンがそのスコープをカバーしていない場合、OAuth 2.0 フローが開始されます。ここで、oauth2SignIn 関数は、ステップ 2 で提供されたもの(および後で完全な例で提供されるもの)と同じです。
var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'; 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 スニペットは、Google API クライアント ライブラリ for JavaScript を使用せずに 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
クロスアカウント保護機能の実装方法と、利用可能なイベントの一覧については、 クロスアカウント保護機能でユーザー アカウントを保護する をご覧ください。