概要
きめ細かな権限により、ユーザーは各アプリと共有するアカウント データをより細かく制御できます。これにより、ユーザーとデベロッパーの双方に、より高い制御性、透明性、セキュリティが提供されます。このガイドでは、きめ細かい権限を処理するようにアプリケーションを更新するために必要な変更と手順について説明します。
きめ細かい権限とは
たとえば、メールとカレンダーの両方のスコープをリクエストする生産性向上アプリを開発するとします。ユーザーは、Gmail ではなく Google カレンダーでのみアプリケーションを使用したい場合があります。きめ細かな OAuth 権限を使用すると、ユーザーは Gmail ではなく Google カレンダーの権限のみを付与できます。ユーザーが特定のデータへのアクセスを許可できるようにすることで、データの露出を最小限に抑え、信頼性を高め、ユーザーがプライバシー重視の管理でデジタル ライフを管理できるようにします。このようなシナリオを処理するようにアプリケーションを設計することが重要です。
ログイン以外のスコープが複数リクエストされている場合
ログイン スコープとログイン以外のスコープ
ログイン スコープとログイン以外のスコープの両方をリクエストするアプリケーションの場合、ユーザーにはまずログイン スコープ(email、profile、openid)の同意ページが表示されます。ユーザーが基本的な ID 情報(名前、メールアドレス、プロフィール写真)の共有に同意すると、ログイン以外のスコープの詳細な権限の同意画面が表示されます。この場合、アプリケーションはユーザーから付与されたスコープを確認する必要があります。ユーザーがリクエストされたすべてのスコープを付与しているとは限りません。次の例では、ウェブ アプリケーションが 3 つのログイン スコープすべてと、Google ドライブのログイン以外のスコープをリクエストしています。ユーザーがログイン スコープに同意すると、Google ドライブの権限に関するきめ細かい権限の同意画面が表示されます。
複数のログイン以外のスコープ
アプリケーションが複数のログイン以外のスコープをリクエストすると、ユーザーに詳細な権限の同意画面が表示されます。ユーザーは、アプリと共有することを承認する権限を選択できます。以下は、ユーザーの Gmail メッセージと Google カレンダー データへのアクセスをリクエストする、きめ細かい権限の同意画面の例です。
ログイン スコープ(email、profile、openid)のみをリクエストするアプリケーションの場合、詳細な権限の同意画面は適用されません。ユーザーはログイン リクエスト全体を承認または拒否します。つまり、アプリがログイン スコープ(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 earlier. * 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 });
送信ネットワーク呼び出しを検査する
ネットワーク呼び出しを検査する方法は、アプリケーションの種類によって異なります。
- ウェブ アプリケーション - Chrome でネットワーク アクティビティを検査する
- Android - ネットワーク インスペクタでネットワーク トラフィックを検査する
- Chrome アプリ
- Chrome 拡張機能のページに移動します。
- 拡張機能ページの右上にある [デベロッパー モード] チェックボックスをオンにします。
- モニタリングする拡張機能を選択します。
- 拡張機能ページの [ビューを検証] セクションにある [バックグラウンド ページ] リンクをクリックします。
- [デベロッパー ツール] ダイアログが開き、[ネットワーク] タブでネットワーク トラフィックをモニタリングできます。
- iOS - Instruments を使用した HTTP トラフィックの分析
- デスクトップ アプリ - アプリの開発対象のオペレーティング システムで使用可能なネットワーク キャプチャ ツールを使用します。
ネットワーク呼び出しを検査する際は、Google OAuth 認可エンドポイントに送信されたリクエストを探し、scope パラメータを調べます。
これらの値により、詳細な権限の同意画面が表示されます。
scopeパラメータに、ログイン スコープとログイン以外のスコープが含まれています。次のリクエストの例には、3 つのログイン スコープと、ユーザーの Google ドライブ ファイルのメタデータを表示するための 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
きめ細かい権限を処理するためのベスト プラクティス
きめ細かい権限を処理するためにアプリケーションを更新する必要があると判断した場合は、複数のスコープに対する同意を適切に処理するために、コードに必要な更新を行う必要があります。すべてのアプリケーションは、次のベスト プラクティスに準拠する必要があります。
- Google API サービス: ユーザーデータに関するポリシーを確認し、ポリシーに準拠していることを確認します。
- タスクに必要な特定のスコープをリクエストします。必要なスコープのみをリクエストするという Google OAuth 2.0 ポリシーを遵守する必要があります。アプリのコア機能に不可欠な場合を除き、ログイン時に複数のスコープをリクエストすることは避けてください。複数のスコープをバンドルすると、特にアプリの機能に不慣れな初回ユーザーにとって、これらの権限の必要性を理解することが難しくなる可能性があります。これにより、ユーザーが警戒し、アプリケーションの利用を控える可能性があります。
- 承認リクエストを求める前に、ユーザーに理由を提供します。リクエストされた権限がアプリに必要な理由、ユーザーのデータの用途、リクエストを承認することでユーザーが得られるメリットを明確に説明します。Google の調査によると、これらの説明により、ユーザーの信頼とエンゲージメントが向上します。
- アプリケーションがスコープをリクエストするたびに増分認証を使用して、複数のアクセス トークンを管理する必要がないようにします。
- ユーザーが付与したスコープを確認します。複数のスコープを一度にリクエストすると、ユーザーがアプリからリクエストされたすべてのスコープを付与しない可能性があります。アプリは、ユーザーによって付与されたスコープを常に確認し、スコープが拒否された場合は関連する機能を無効にする必要があります。複数のスコープに対する同意の処理に関する Google OAuth 2.0 ポリシーに沿って、スコープを必要とする特定の機能を使用する意図をユーザーが明確に示した場合にのみ、再度同意を求めるようにしてください。
きめ細かい権限を処理するようにアプリケーションを更新する
Android アプリ
Google OAuth 2.0 とのやり取りに使用する SDK のドキュメントを参照し、ベスト プラクティスに基づいて、きめ細かい権限を処理するようにアプリを更新する必要があります。
Play 開発者サービスの auth.api.signin SDK を使用して Google OAuth 2.0 を操作する場合は、requestPermissions 関数を使用して必要な最小限のスコープセットをリクエストし、hasPermissions 関数を使用して、詳細な権限をリクエストしたときにユーザーが付与したスコープを確認できます。
Chrome 拡張機能アプリケーション
ベスト プラクティスに基づいて、Chrome Identity API を使用して Google OAuth 2.0 を操作する必要があります。
次の例は、詳細な権限を適切に処理する方法を示しています。
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 コンソールの [クライアント] ページで、パブリック エンドポイントのリダイレクト 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 earlier
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 the Google authorization server.
if (req.url == '/') {
res.writeHead(301, { "Location": authorizationUrl });
}
// Receive the callback from the Google authorization server.
if (req.url.startsWith('/oauth2callback')) {
// Handle the Google authorization 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 earlier
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 the Google authorization server.
if (req.url == '/') {
res.writeHead(301, { "Location": authorizationUrl });
}
// Receive the callback from the Google authorization server.
if (req.url.startsWith('/oauth2callback')) {
// Handle the Google authorization 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 認証エンドポイントを直接呼び出すアプリケーションの場合は、詳細な権限の処理に関するこちらのドキュメントをご覧ください。
きめ細かな権限の処理について、更新したアプリをテストする
- ユーザーが権限リクエストに応答できるすべてのケースと、アプリに期待される動作を概説します。たとえば、ユーザーがリクエストされた 3 つのスコープのうち 2 つのみを承認した場合、アプリケーションはそれに応じて動作する必要があります。
きめ細かい権限を有効にしてアプリをテストします。きめ細かい権限を有効にする方法は 2 つあります。
- アプリケーションの OAuth 2.0 同意画面をチェックして、アプリケーションで詳細な権限がすでに有効になっているかどうかを確認します。テスト目的で、Google Cloud コンソールから新しいウェブ、Android、iOS の Google OAuth 2.0 クライアント ID を作成することもできます。これらのクライアント ID では、きめ細かい権限が常に有効になっています。
Google OAuth 認可エンドポイントを呼び出すときに、パラメータ
enable_granular_consentをtrueに設定します。一部の SDK では、このパラメータが明示的にサポートされています。その他の場合は、ドキュメントでこのパラメータとその値を手動で追加する方法を確認してください。実装でパラメータの追加がサポートされていない場合は、前述のように、テスト目的でのみ Google Cloud コンソールから新しいウェブ、Android、iOS の Google OAuth 2.0 クライアント ID を作成できます。
更新したアプリをテストする場合は、Workspace アカウントではなく、個人の Google アカウント(@gmail.com)を使用してください。これは、ドメイン全体の権限委任が設定されている、または信頼できるとマークされている Workspace Enterprise アプリは、現時点ではきめ細かい権限の変更の影響を受けないためです。そのため、組織の Workspace アカウントでテストすると、新しい詳細な同意画面が意図したとおりに表示されないことがあります。