きめ細かい権限を処理する方法

概要

きめ細かい権限により、ユーザーは各アプリと共有するアカウント データをより細かく制御できます。これにより、制御、透明性、セキュリティが強化され、ユーザーとデベロッパーの両方にメリットがあります。このガイドでは、アプリを更新してきめ細かい権限を処理するために必要な変更と手順について説明します。

きめ細かい権限とは

たとえば、メールとカレンダーの両方のスコープをリクエストする生産性向上アプリを開発するとします。ユーザーは、Gmail ではなく Google カレンダーでのみアプリケーションを使用したい場合があります。きめ細かい OAuth 権限を使用すると、ユーザーは Gmail ではなく Google カレンダーの権限のみを付与できます。ユーザーが特定のデータへのアクセスを許可できるようにすることで、データ漏洩を最小限に抑え、信頼性を高め、ユーザーがプライバシーを最優先にデジタル ライフを管理できるようにします。このようなシナリオに対応するようにアプリケーションを設計することが重要です。

ログイン以外のスコープが複数リクエストされた場合

ログイン スコープと非ログイン スコープ

ログイン スコープと非ログイン スコープの両方をリクエストするアプリの場合、ユーザーにはまず、ログイン スコープemailprofileopenid)の同意ページが表示されます。ユーザーが基本的な個人情報(名前、メールアドレス、プロフィール写真)の共有に同意すると、非ログイン スコープの詳細な権限の同意画面が表示されます。この場合、アプリケーションはユーザーが付与したスコープを確認する必要があります。ユーザーがリクエストされたすべてのスコープを付与したと想定することはできません。次の例では、ウェブ アプリケーションが 3 つのログイン スコープと Google ドライブのログイン以外のスコープをリクエストしています。ユーザーがログイン スコープに同意すると、Google ドライブの権限に関するきめ細かい権限の同意画面が表示されます。

ログイン スコープと非ログイン スコープ

ログイン以外のスコープが複数ある

アプリケーションが 2 つ以上のログイン以外のスコープをリクエストすると、ユーザーにきめ細かい権限の同意画面が表示されます。ユーザーは、アプリと共有する権限を選択できます。ユーザーの Gmail メッセージと Google カレンダーのデータへのアクセスをリクエストする、きめ細かい権限の同意画面の例を次に示します。

ログイン以外のスコープが複数ある

ログイン スコープemailprofileopenid)のみをリクエストするアプリには、きめ細かい権限の同意画面は適用されません。ユーザーは、ログイン リクエスト全体を承認または拒否します。つまり、アプリがログイン スコープ(1 つ、2 つ、または 3 つすべて)のみをリクエストする場合、きめ細かい権限の同意画面は適用されません。

ログイン以外のスコープを 1 つだけリクエストするアプリの場合、きめ細かい権限の同意画面は適用されません。つまり、ユーザーはリクエスト全体を承認または拒否します。同意画面にチェックボックスはありません。次の表は、きめ細かい権限の同意画面が表示されるタイミングをまとめたものです。

ログイン スコープの数 ログインなしのスコープの数 きめ細かい権限の同意画面
1~3 0 該当なし
1~3 1+ 該当
0 1 該当なし
0 2+ 該当

アプリケーションが影響を受けるかどうかを判断する

権限リクエストに Google OAuth 2.0 認可エンドポイントが使用されているアプリケーション内のすべてのセクションを徹底的に確認します。複数のスコープをリクエストするアプリは、ユーザーに表示されるきめ細かい権限の同意画面を有効にするため、注意が必要です。このような場合、ユーザーが一部のスコープのみを承認した場合を処理できるようにコードを作成してください。

アプリケーションが複数のスコープを使用しているかどうかを判断する方法

アプリのコードまたは送信ネットワーク呼び出しを調べて、アプリが行う Google OAuth 2.0 の承認リクエストによって、きめ細かい権限の同意画面が表示されるかどうかを確認します。

アプリケーション コードを検査する

Google OAuth 認可エンドポイントを呼び出してユーザーに権限をリクエストしているアプリケーション コードのセクションを確認します。Google API クライアント ライブラリのいずれかを使用している場合は、クライアントの初期化手順で、アプリケーションがリクエストするスコープを確認できます。次のセクションにいくつかの例を示します。アプリケーションが Google OAuth 2.0 を処理するために使用する SDK のドキュメントを参照し、次の例に示すガイダンスを参考にして、アプリケーションが影響を受けるかどうかを判断する必要があります。

Google Identity Services

次の Google Identity Services JavaScript ライブラリのコード スニペットは、ログイン以外の複数のスコープで TokenClient を初期化します。ウェブアプリがユーザーに承認をリクエストすると、きめ細かい権限の同意画面が表示されます。

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

Python

次のコード スニペットは、google-auth-oauthlib.flow モジュールを使用して認証リクエストを作成する方法を示しています。scope パラメータには、ログイン以外の 2 つのスコープが含まれています。きめ細かい権限の同意画面は、ウェブ アプリケーションがユーザーに承認をリクエストするときに表示されます。

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/calendar.readonly',
                    'https://www.googleapis.com/auth/contacts.readonly'])

Node.js

次のコード スニペットでは、google.auth.OAuth2 オブジェクトを作成します。このオブジェクトは、scope パラメータに 2 つの非ログイン スコープを含む認可リクエストのパラメータを定義します。きめ細かい権限の同意画面は、ウェブアプリがユーザーに承認をリクエストしたときに表示されます。

const {google} = require('googleapis');

/**
  * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI
  * from the client_secret.json file. To get these credentials for your application, visit
  * https://console.cloud.google.com/apis/credentials.
  */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Calendar and Contacts.
const scopes = [
  'https://www.googleapis.com/auth/calendar.readonly',
  'https://www.googleapis.com/auth/contacts.readonly']
];

// Generate a url that asks permissions
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined above.
    * Alternatively, if only one scope is needed, you can pass a scope URL as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true
});

送信ネットワーク通話を検査する

ネットワーク呼び出しを検査する方法は、アプリケーション クライアントのタイプによって異なります。

ネットワーク呼び出しを検査する際は、Google OAuth 認可エンドポイントに送信されたリクエストを探し、scope パラメータを調べます。

これらの値は、詳細なアクセス許可の同意画面を表示させます

  • scope パラメータに、ログイン スコープとログイン以外のスコープが含まれています。

    次のサンプル リクエストには、ユーザーの Google ドライブ ファイルのメタデータを表示するための 3 つのログイン スコープと 1 つの非ログイン スコープが含まれています。

    https://accounts.google.com/o/oauth2/v2/auth?
    access_type=offline&
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
    include_granted_scopes=true&
    response_type=code&
    redirect_uri=YOUR_REDIRECT_URL&
    client_id=YOUR_CLIENT_ID
  • scope パラメータに、ログイン以外のスコープが複数含まれています。

    次のサンプル リクエストには、ユーザーの Google ドライブのメタデータを表示し、特定の Google ドライブ ファイルを管理するための、ログイン以外の 2 つのスコープが含まれています。

  • https://accounts.google.com/o/oauth2/v2/auth?
    access_type=offline&
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&
    include_granted_scopes=true&
    response_type=code&
    redirect_uri=YOUR_REDIRECT_URL&
    client_id=YOUR_CLIENT_ID

きめ細かい権限を処理するためのベスト プラクティス

アプリケーションを更新して粒度の細かい権限を処理する必要があると判断した場合は、複数のスコープの同意を適切に処理するために、コードに必要な更新を行う必要があります。すべてのアプリケーションは、次のベスト プラクティスを遵守する必要があります。

  1. Google API サービス: ユーザーデータに関するポリシー確認し、準拠していることを確認します。
  2. タスクに必要な特定のスコープをリクエストします。必要なスコープのみをリクエストする Google OAuth 2.0 ポリシーに準拠する必要があります。アプリのコア機能に不可欠な場合を除き、ログイン時に複数のスコープをリクエストすることは避けるべきです。複数のスコープをまとめてリクエストすると、特にアプリの機能をよく知らない初回ユーザーは、これらの権限が必要な理由を理解するのが難しくなる可能性があります。これにより、ユーザーがアラームを認識し、アプリの利用を控える可能性があります。
  3. 承認リクエストを求める前に、ユーザーに理由を説明します。リクエストされた権限がアプリに必要な理由、ユーザーデータの用途、リクエストを承認することでユーザーが得られるメリットを明確に説明します。Google の調査によると、このような説明はユーザーの信頼とエンゲージメントを高めることがわかっています。
  4. アプリケーションがスコープをリクエストするたびに、増分認可を使用します。これにより、複数のアクセス トークンを管理する必要がなくなります。
  5. ユーザーがどのスコープを付与したかを確認します。複数のスコープを一度にリクエストすると、ユーザーはアプリがリクエストしたすべてのスコープを付与しない可能性があります。アプリは、ユーザーによってどのスコープが許可されたかを常に確認し、関連する機能を無効にすることでスコープの拒否に対処する必要があります。複数のスコープの同意の処理に関する Google OAuth 2.0 ポリシーに沿って、スコープを必要とする特定の機能を使用する意思をユーザーが明確に示した場合にのみ、ユーザーに同意を再度求めるようにしてください。

きめ細かい権限を処理するようにアプリを更新する

Android アプリ

Google OAuth 2.0 とのやり取りに使用する SDK のドキュメントを参照し、ベスト プラクティスに基づいてきめ細かい権限を処理するようにアプリケーションを更新する必要があります。

Google OAuth 2.0 とのやり取りに Play 開発者サービスの auth.api.signin SDK を使用している場合は、requestPermissions 関数を使用して必要な最小限のスコープのセットをリクエストし、hasPermissions 関数を使用して、ユーザーが粒度の細かい権限をリクエストしたときにどのスコープを付与したかを確認できます。

Chrome 拡張機能アプリケーション

ベスト プラクティスに基づいて Google OAuth 2.0 を使用するには、Chrome Identity API を使用する必要があります。

次の例は、きめ細かい権限を適切に処理する方法を示しています。

manifest.json

このマニフェスト ファイルの例では、Chrome 拡張機能アプリケーションの 2 つの非ログイン スコープを宣言しています。

{
  "name": "Example Chrome extension application",
  ...
  "permissions": [
      "identity"
    ],
  "oauth2" : {
      "client_id": "YOUR_CLIENT_ID",
      "scopes":["https://www.googleapis.com/auth/calendar.readonly",
                "https://www.googleapis.com/auth/contacts.readonly"]
  }
}

アプローチが間違っている

全か無か

ユーザーがボタンをクリックして、承認プロセスを開始します。このコード スニペットは、manifest.json ファイルで指定された 2 つのスコープについて、ユーザーに「すべて承認」の同意画面が表示されることを前提としています。ユーザーがどのスコープを付与したかを確認していません。

oauth.js

...
document.querySelector('button').addEventListener('click', function () {
  chrome.identity.getAuthToken({ interactive: true },
      function (token) {
          if (token === undefined) {
            // User didn't authorize both scopes.
            // Updating the UX and application accordingly
            ...
          } else {
            // User authorized both or one of the scopes.
            // It neglects to check which scopes users granted and assumes users granted all scopes.

            // Calling the APIs, etc.
            ...
          }
      });
});

正しいアプローチ

最小スコープ

必要な最小限のスコープを選択する

アプリケーションは、必要な最小限のスコープのみをリクエストする必要があります。タスクを完了するために必要な場合は、アプリケーションが一度に 1 つのスコープをリクエストすることが推奨されます。

この例では、manifest.json ファイルで宣言された両方のスコープが、必要な最小限のスコープのセットであると想定しています。oauth.js ファイルは、Chrome Identity API を使用して Google との認証プロセスを開始します。 きめ細かい権限を有効にすることをおすすめします。これにより、ユーザーはアプリに付与する権限をより細かく制御できるようになります。ユーザーが承認したスコープを確認して、ユーザーからのレスポンスを適切に処理する必要があります。

oauth.js

...
document.querySelector('button').addEventListener('click', function () {
  chrome.identity.getAuthToken({ interactive: true, enableGranularPermissions: true },
      function (token, grantedScopes) {
          if (token === undefined) {
            // User didn't authorize any scope.
            // Updating the UX and application accordingly
            ...
          } else {
            // User authorized the request. Now, check which scopes were granted.
            if (grantedScopes.includes('https://www.googleapis.com/auth/calendar.readonly'))
            {
              // User authorized Calendar read permission.
              // Calling the APIs, etc.
              ...
            }
            else
            {
              // User didn't authorize Calendar read permission.
              // Update UX and application accordingly
              ...
            }

            if (grantedScopes.includes('https://www.googleapis.com/auth/contacts.readonly'))
            {
              // User authorized Contacts read permission.
              // Calling the APIs, etc.
              ...
            }
            else
            {
              // User didn't authorize Contacts read permission.
              // Update UX and application accordingly
              ...
            }
          }
      });
});

iOS、iPadOS、macOS アプリケーション

Google OAuth 2.0 とのやり取りに使用する SDK のドキュメントを参照し、ベスト プラクティスに基づいてきめ細かい権限を処理するようにアプリケーションを更新する必要があります。

iOS および macOS 向けの Google ログイン ライブラリを使用して Google OAuth 2.0 とやり取りする場合は、きめ細かい権限の処理に関するドキュメントを確認してください。

ウェブ アプリケーション

Google OAuth 2.0 とのやり取りに使用する SDK のドキュメントを参照し、ベスト プラクティスに基づいてきめ細かい権限を処理するようにアプリケーションを更新する必要があります。

サーバーサイド(オフライン)アクセス

サーバーサイド(オフライン)アクセスモードでは、次の操作を行う必要があります。
  • サーバーを立ち上げ、認証コードを受信する一般公開のエンドポイントを定義します。
  • Google Cloud コンソールの Clients page で、パブリック エンドポイントの リダイレクト URI を構成します。

次のコード スニペットは、2 つの非ログイン スコープをリクエストする NodeJS の例を示しています。ユーザーには、きめ細かい権限の同意画面が表示されます。

アプローチが間違っている

全か無か

ユーザーが認証 URL にリダイレクトされます。このコード スニペットは、ユーザーに scopes 配列で指定された 2 つのスコープの「全か無か」の同意画面が表示されることを前提としています。ユーザーがどのスコープを付与したかを確認していません。

main.js

...
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes - Google Calendar and Contacts
const scopes = [
  'https://www.googleapis.com/auth/contacts.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a url that asks permissions for the Google Calendar and Contacts scopes
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  // Pass in the scopes array defined above
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true
});

async function main() {
  const server = http.createServer(async function (req, res) {
    // Example on redirecting user to Google OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from Google OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google OAuth 2.0 server response
      let q = url.parse(req.url, true).query;

      if (q.error) {
        // User didn't authorize both scopes.
        // Updating the UX and application accordingly
        ...
      } else {
        // User authorized both or one of the scopes.
        // It neglects to check which scopes users granted and assumes users granted all scopes.

        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        // Calling the APIs, etc.
        ...
      }
    }
    res.end();
  }).listen(80);
}
正しいアプローチ

最小スコープ

必要な最小限のスコープを選択する

アプリケーションは、必要な最小限のスコープのみをリクエストする必要があります。タスクを完了するために必要な場合は、アプリケーションが一度に 1 つのスコープをリクエストすることが推奨されます。アプリケーションがスコープをリクエストするときは、複数のアクセス トークンを管理する必要がないように、増分認証を使用する必要があります。

アプリケーションで複数の非ログイン スコープをリクエストする必要がある場合は、リクエスト時に常に増分認証を使用し、ユーザーが付与したスコープを確認する必要があります。

この例では、アプリが適切に機能するには、両方のスコープが必要であると想定しています。 きめ細かい権限を有効にすることをおすすめします。これにより、ユーザーはアプリに付与する権限をより細かく制御できるようになります。アプリケーションは、ユーザーが承認したスコープを確認して、ユーザーからのレスポンスを適切に処理する必要があります。

main.js

...
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes - Google Calendar and Contacts
const scopes = [
  'https://www.googleapis.com/auth/contacts.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a url that asks permissions for the Google Calendar and Contacts scopes
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  // Pass in the scopes array defined above
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true,
  // Set to true to enable more granular permissions for Google OAuth 2.0 client IDs created before 2019.
  // No effect for newer Google OAuth 2.0 client IDs, since more granular permissions is always enabled for them.
  enable_granular_consent: true
});

async function main() {
  const server = http.createServer(async function (req, res) {
    // Redirect users to Google OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from Google OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google OAuth 2.0 server response
      let q = url.parse(req.url, true).query;

      if (q.error) {
        // User didn't authorize both scopes.
        // Updating the UX and application accordingly
        ...
      } else {
        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        oauth2Client.setCredentials(tokens);

        // User authorized the request. Now, check which scopes were granted.
        if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly'))
        {
          // User authorized Calendar read permission.
          // Calling the APIs, etc.
          ...
        }
        else
        {
          // User didn't authorize Calendar read permission.
          // Calling the APIs, etc.
          ...
        }

        // Check which scopes user granted the permission to application
        if (tokens.scope.includes('https://www.googleapis.com/auth/contacts.readonly'))
        {
          // User authorized Contacts read permission.
          // Calling the APIs, etc.
          ...
        }
        else
        {
          // User didn't authorize Contacts read permission.
          // Update UX and application accordingly
          ...
        }
      }
    }
    res.end();
  }).listen(80);
}

サーバーベースのアプリケーションから Google API にアクセスする方法については、 サーバーサイド ウェブアプリのガイドをご覧ください。

クライアントサイドのみのアクセス

  • Google Identity Services JavaScript ライブラリを使用して Google OAuth 2.0 とやり取りするアプリケーションの場合は、きめ細かい権限の処理に関するこちらのドキュメントをご確認ください。
  • JavaScript を使用して Google OAuth 2.0 認証エンドポイントに直接呼び出しを行うアプリケーションについては、きめ細かい権限の処理に関するこちらのドキュメントをご覧ください。

更新されたアプリで、きめ細かい権限の処理をテストする

  1. ユーザーが権限リクエストに応答できるすべてのケースと、アプリの想定される動作を概説します。たとえば、ユーザーがリクエストされた 3 つのスコープのうち 2 つのみを承認した場合、アプリケーションはそれに応じて動作する必要があります。
  2. きめ細かい権限を有効にしてアプリケーションをテストします。きめ細かい権限を有効にする方法は 2 つあります。
    1. アプリケーションの OAuth 2.0 同意画面で、アプリケーションに対してきめ細かい権限がすでに有効になっているかどうかを確認します。Google Cloud コンソールで、テスト用に新しいウェブ、Android、iOS の Google OAuth 2.0 クライアント ID を作成することもできます。これらの ID では、常にきめ細かい権限が有効になっています。
    2. Google OAuth 認可エンドポイントを呼び出すときに、パラメータ enable_granular_consenttrue に設定します。一部の SDK では、このパラメータが明示的にサポートされています。その他の場合は、ドキュメントで、このパラメータとその値を手動で追加する方法をご確認ください。実装でパラメータの追加がサポートされていない場合は、前述のとおり、テスト目的でのみ Google Cloud コンソールから新しいウェブ、Android、iOS の Google OAuth 2.0 クライアント ID を作成できます。
  3. 更新したアプリをテストする際は、Workspace アカウントではなく個人の Google アカウント(@gmail.com)を使用してください。これは、ドメイン全体の権限の委任が設定されているか、信頼できるとマークされている Workspace Enterprise アプリは、現時点ではきめ細かい権限の変更の影響を受けないためです。そのため、組織の Workspace アカウントでテストしても、新しい詳細な同意画面が意図したとおりに表示されない可能性があります。