トークンモデルの使用

google.accounts.oauth2 JavaScript ライブラリを使用すると、ユーザーの同意を求めて、ユーザーデータの操作に必要なアクセス トークンを取得できます。これは OAuth 2.0 の暗黙的付与フローをベースにしており、REST と CORS を使用して Google API を直接呼び出すか、JavaScript 用の Google API クライアント ライブラリgapi.client)を使用して、より複雑な API にシンプルかつ柔軟にアクセスできるように設計されています。

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

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

古い クライアント側ウェブ アプリケーションの OAuth 2.0 ガイドで説明されている手法ではなく、ここで説明するアプローチを使用することをおすすめします。

前提条件

設定の手順に沿って、OAuth 同意画面を構成し、クライアント ID を取得して、クライアント ライブラリを読み込みます。

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

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 はユーザーに以下の操作を求めます。

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

ユーザーのジェスチャーによってトークン フローがトリガーされる: <button onclick="client.requestAccessToken();">Authorize me</button>

Google は、アクセス トークンと、ユーザーがアクセスを許可したスコープのリストを含む TokenResponse をコールバック ハンドラに返します。エラーが返されることもあります。

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

アプリの設計とユーザー エクスペリエンスは、Google の OAuth 2.0 ポリシーを十分に確認したうえで実装する必要があります。これらのポリシーには、複数のスコープの使用、ユーザーの同意を処理するタイミングと方法などが含まれます。

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

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

ただし、例外もあります。ドメイン全体の権限の委任が設定されている Google Workspace Enterprise アプリ、または [信頼できる] とマークされているアプリは、詳細な権限の同意画面をスキップします。これらのアプリでは、ユーザーに詳細な権限の同意画面は表示されません。代わりに、アプリはリクエストされたスコープをすべて受信するか、まったく受信しません。

詳細については、きめ細かい権限を処理する方法をご覧ください。

段階的な認可

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

  • シングルページ Ajax アプリ。多くの場合、XMLHttpRequest を使用してリソースに動的にアクセスします。
  • 複数のウェブページ、リソースは分離され、ページごとに管理されます。

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

Ajax

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() への複数の呼び出しで保持されます。デフォルトでは、ユーザーがウェブサイトにアクセスして新しいスコープをリクエストしたときにのみユーザーの同意が必要ですが、Token Client 構成オブジェクトの 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 APIs JavaScript ライブラリを使用する

トークン クライアントは Google API Client Library for JavaScript と連携します。以下のコード スニペットを参照してください。

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);
  });