トークンモデルの使用

google.accounts.oauth2 JavaScript ライブラリは、ユーザーの同意を求めるプロンプトと、ユーザーデータを扱うアクセス トークンを取得する際に役立ちます。これは OAuth 2.0 の暗黙権限付与フローをベースにしており、REST と CORS を使用して Google API を直接呼び出すことも、Google の JavaScript 用 Google API クライアント ライブラリgapi.client)を使用して、より複雑な API への簡単かつ柔軟なアクセスを可能にすることもできます。

保護されたユーザーデータにブラウザからアクセスする前に、サイトのユーザーが Google のウェブベースのアカウント選択ツール、ログイン、同意プロセスをトリガーし、最後に 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 からユーザーに次の操作を行うよう促されます。

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

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

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

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

アプリのデザインとユーザー エクスペリエンスは、Google の OAuth 2.0 ポリシーを入念に審査した後で実装する必要があります。このポリシーでは、複数のスコープの使用、ユーザーの同意を処理するタイミングと方法などについて説明します。

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

このプロセス中に、Google はユーザーの同意を求めるプロンプトを表示し、リクエストされた各スコープを個別に一覧表示して、ユーザーがアプリと共有するリソースを選択します。最後に、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() への複数の呼び出しで維持されます。デフォルトでは、ユーザーの同意は、ユーザーが初めてウェブサイトにアクセスして新しいスコープをリクエストする場合にのみ必要ですが、トークン クライアントの config オブジェクトの 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);
  });