トークンモデルの使用

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