トークンモデルの使用

google.accounts.oauth2 JavaScript ライブラリを使用すると、ユーザーの同意を求め、ユーザーデータを扱うアクセス トークンを取得できます。OAuth 2.0 の暗黙的な権限付与フローに基づいており、REST と CORS を使用して Google API を直接呼び出せるか、JavaScript 用の Google API クライアント ライブラリgapi.client とも呼ばれます)を使用して、より複雑な API に簡単かつ柔軟にアクセスできるように設計されています。

保護されたユーザーデータにブラウザからアクセスする前に、サイトのユーザーがウェブベースのアカウント選択ツール、ログイン プロセス、同意プロセスをトリガーし、最後に Google の OAuth サーバーで問題を提起して、ウェブアプリにアクセス トークンを返します。

トークンベースの認証モデルでは、ユーザーごとの更新トークンをバックエンド サーバーに保存する必要はありません。

以前のクライアントサイド ウェブ アプリケーション用の OAuth 2.0 ガイドで紹介されていた手法ではなく、ここで説明する手法を採用することをおすすめします。

設定

Google API クライアント ID の取得ガイドに記載されている手順に沿って、クライアント ID を検索または作成します。次に、Google API を呼び出すサイトにクライアント ライブラリを追加します。最後に、トークン クライアントを初期化します。通常、これはクライアント ライブラリの onload ハンドラ内で行います。

トークン クライアントを初期化する

initTokenClient() を呼び出して、ウェブアプリのクライアント ID で新しいトークン クライアントを初期化します。必要に応じて、ユーザーがアクセスする必要がある 1 つ以上のスコープのリストを指定できます。

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (response) => {
    ...
  },
});

OAuth 2.0 トークンフローをトリガーする

requestAccessToken() メソッドを使用して、トークン UX フローをトリガーし、アクセス トークンを取得します。ユーザーに以下の操作を求めるメッセージが表示されます。

  • アカウントを選択し、
  • Google アカウントにログイン(まだログインしていない場合)
  • リクエストされた各スコープにウェブアプリがアクセスすることに同意する。

ユーザー操作によってトークンフロー <button onclick="client.requestAccessToken();">Authorize me</button> がトリガーされる

Google は、アクセス トークンとユーザーがアクセス権を付与したスコープのリストを含む TokenResponse を返すか、コールバック ハンドラにエラーを返します。

ユーザーはアカウント選択ツールまたはログイン ウィンドウを閉じることができます。その場合、コールバック関数は呼び出されません。

アプリのデザインやユーザー エクスペリエンスは、Google の OAuth 2.0 ポリシーを十分に検討したうえで実装する必要があります。これらのポリシーは、複数のスコープの設定や、ユーザーの同意を処理するタイミングや方法などを対象としています。

増分認可とは、事前にすべてを一度にリクエストするのではなく、必要に応じてスコープを使用してリソースへのアクセスをリクエストする際に使用する、ポリシーとアプリの設計手法です。ユーザーは、アプリがリクエストした個々のリソースの共有を承認または拒否できます。これをきめ細かい権限と呼びます。

このプロセス中に、リクエストされた各スコープを個々に一覧表示して、ユーザーの同意を求めます。ユーザーはアプリと共有するリソースを選択します。最後に、Google はコールバック関数を呼び出して、アクセス トークンとユーザー承認のスコープを返します。これにより、アプリはきめ細かい権限を使用することで、さまざまな結果を安全に処理できます。

増分承認

ウェブアプリの場合、次の 2 つの大まかなシナリオで、次を使用した増分認可を示します。

  • 単一ページの Ajax アプリ。多くの場合、リソースへの動的アクセスが可能な XMLHttpRequest を使用します。
  • 複数のウェブページやリソースは分離され、ページ単位で管理されている。

これら 2 つのシナリオは、設計上の考慮事項と手法を説明するために提示するものであり、同意をアプリに組み込む方法について包括的な推奨事項を示すものではありません。実際のアプリでは、これらの手法のバリエーションまたは組み合わせを使用する場合があります。

アヤックス

アプリに増分承認のサポートを追加するため、requestAccessToken() を複数回呼び出し、OverridableTokenClientConfig オブジェクトの scope パラメータを使用して、個々のスコープを必要なときに、必要な場合にのみリクエストします。この例では、ユーザーの操作によって折りたたまれたコンテンツのセクションが展開された後にのみ、リソースがリクエストされて表示されます。

Ajax アプリ
ページの読み込み時にトークン クライアントを初期化します。
        const client = google.accounts.oauth2.initTokenClient({
          client_id: 'YOUR_GOOGLE_CLIENT_ID',
          callback: "onTokenResponse",
        });
      
ユーザー操作によって同意をリクエストし、アクセス トークンを取得して、[+] をクリックして開きます。

読むドキュメント

最近のドキュメントを表示

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/documents.readonly'
             })
           );
        

今後のイベント

カレンダー情報を表示

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/calendar.readonly'
             })
           );
        

写真を表示する

          client.requestAccessToken(
            overrideConfig = ({
               scope = 'https://www.googleapis.com/auth/photoslibrary.readonly'
             })
           );
        

requestAccessToken を呼び出すたびにユーザーの同意が得られ、アプリは、ユーザーが展開を選択したセクションで必要なリソースにのみアクセスできるため、ユーザーの選択によるリソース共有が制限されます。

複数のウェブページ

段階的な承認を設計する場合、複数のページを使用して、ページの読み込みに必要なスコープのみをリクエストするため、複雑さが軽減され、ユーザーの同意を得てアクセス トークンを取得するために複数回呼び出す必要がなくなります。

マルチページ アプリ
ウェブページ コード
ページ 1:読むドキュメント
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/documents.readonly',
  });
  client.requestAccessToken();
          
ページ 2:今後のイベント
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/calendar.readonly',
  });
  client.requestAccessToken();
          
ページ 3:写真カルーセル
  const client = google.accounts.oauth2.initTokenClient({
    client_id: 'YOUR_GOOGLE_CLIENT_ID',
    callback: "onTokenResponse",
    scope: 'https://www.googleapis.com/auth/photoslibrary.readonly',
  });
  client.requestAccessToken();
          

各ページは、読み込み時に initTokenClient()requestAccessToken() を呼び出して、必要なスコープをリクエストし、アクセス トークンを取得します。このシナリオでは、個々のウェブページを使用して、ユーザーの機能とリソースをスコープごとに明確に区別します。実際の状況では、個々のページが複数の関連するスコープをリクエストすることがあります。

きめ細かい権限

きめ細かい権限はすべてのシナリオで同じように処理されます。requestAccessToken() がコールバック関数を呼び出し、アクセス トークンが返されたら、ユーザーが hasGrantedAllScopes() または hasGrantedAnyScope() を使用して、リクエストされたスコープを承認していることを確認します。例:

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
          https://www.googleapis.com/auth/documents.readonly \
          https://www.googleapis.com/auth/photoslibrary.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      if (google.accounts.oauth2.hasGrantedAnyScope(tokenResponse,
          'https://www.googleapis.com/auth/photoslibrary.readonly')) {
        // Look at pictures
        ...
      }
      if (google.accounts.oauth2.hasGrantedAllScopes(tokenResponse,
          'https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/documents.readonly')) {
        // Meeting planning and review documents
        ...
      }
    }
  },
});

以前のセッションまたはリクエストで以前に承認された権限も、レスポンスに含まれます。ユーザーの同意の記録は、ユーザーとクライアント ID ごとに保持され、initTokenClient() または requestAccessToken() の複数の呼び出し後も保持されます。デフォルトでは、ユーザーの同意が必要になるのは、ユーザーが初めてウェブサイトにアクセスして新しいスコープをリクエストしたときのみですが、トークン クライアント構成オブジェクトの prompt=consent を使用して、ページの読み込みごとにリクエストできます。

トークンの操作

トークンモデルでは、アクセス トークンは OS やブラウザによって保存されません。代わりに、ページの読み込み時に新しいトークンが取得されます。あるいは、ボタンの押下などのユーザー操作によって requestAccessToken() の呼び出しがトリガーされた後、トークンが取得されます。

Google API での REST と CORS の使用

アクセス トークンを使用すると、REST や CORS を使用する Google API に認証済みのリクエストを行うことができます。これにより、ユーザーがログインして同意し、Google がアクセス トークンを発行して、サイトでユーザーのデータを扱えるようになります。

この例では、tokenRequest() から返されたアクセス トークンを使用して、ログインしているユーザーの今後のカレンダーの予定を表示します。

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + tokenResponse.access_token);
xhr.send();

詳細については、CORS を使用して Google API にアクセスする方法をご覧ください。

次のセクションでは、より複雑な API と簡単に統合する方法について説明します。

Google API JavaScript ライブラリを使用する

トークン クライアントは JavaScript の Google API クライアント ライブラリで動作します。以下のコード スニペットをご覧ください。

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) {
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

トークンの有効期限

設計上、アクセス トークンの存続期間は短くなっています。ユーザーのセッションが終了する前にアクセス トークンの有効期限が切れた場合は、ボタンの押下などのユーザードリブン イベントから requestAccessToken() を呼び出して新しいトークンを取得します。

google.accounts.oauth2.revoke メソッドを呼び出して、アプリに付与されているすべてのスコープについて、ユーザーの同意とリソースへのアクセス権を削除します。この権限を取り消すには、有効なアクセス トークンが必要です。

google.accounts.oauth2.revoke('414a76cb127a7ece7ee4bf287602ca2b56f8fcbf7fcecc2cd4e0509268120bd7', done => {
    console.log(done);
    console.log(done.successful);
    console.log(done.error);
    console.log(done.error_description);
  });