概要
Google API を呼び出すためにユーザーごとのアクセス トークンを取得するために、次の JavaScript ライブラリが提供されています。
このガイドでは、これらのライブラリから Google Identity Services ライブラリへの移行手順を説明します。
このガイドに従うと、次のことができるようになります。
- 非推奨のプラットフォーム ライブラリを Identity Services ライブラリに置き換える。
- API クライアント ライブラリを使用している場合は、非推奨の
gapi.auth2
モジュールとそのメソッド、オブジェクトを削除し、同等の ID サービスに置き換えます。
Identity Services JavaScript ライブラリの変更点については、概要とユーザー認証の仕組みをご覧ください。
ユーザー登録とログインの認証については、Google ログインからの移行をご覧ください。
認可フローを特定する
ユーザー認可フローには、暗黙のコードと認可コードの 2 つがあります。
ウェブアプリを確認し、現在使用されている承認フローの種類を特定します。
ウェブアプリが暗黙的フローを使用していることを示します。
- ウェブアプリは、バックエンド プラットフォームのない、純粋にブラウザベースです。
- ユーザーが Google API を呼び出すために存在している必要があります。アプリはアクセス トークンのみを使用し、更新トークンは必要ありません。
- ウェブアプリで
apis.google.com/js/api.js
を読み込みます。 - 実装はクライアントサイド ウェブ アプリケーション用の OAuth 2.0 に基づいています。
- アプリは、JavaScript の Google API クライアント ライブラリにある
gapi.client
モジュールまたはgapi.auth2
モジュールのいずれかを使用します。
ウェブアプリで認可コードフローが使用されていることを示します。
実装は次の要素に基づいて行われます。
アプリは、ユーザーのブラウザとバックエンド プラットフォームの両方で実行されます。
バックエンド プラットフォームは認証コード エンドポイントをホストします。
バックエンド プラットフォームは、ユーザーが存在することなく Google API を呼び出します(Google はオフライン モードとも呼ばれます)。
更新トークンはバックエンド プラットフォームによって管理、保存されます。
場合によっては、コードベースが両方のフローをサポートすることもあります。
認可フローを選択する
移行を開始する前に、既存のフローを続行するか、別のフローを採用するかが、ニーズに最も合っているかどうかを判断する必要があります。
2 つのフローの主な違いとトレードオフを理解するには、認可フローの選択をご覧ください。
ほとんどの場合、最高レベルのユーザー セキュリティを提供する認証コードフローが推奨されます。このフローを実装すると、プラットフォームが新しいオフライン機能を簡単に追加できるようになります。たとえば、更新を取得する機能によって、カレンダー、写真、サブスクリプションなどに加えられた重要な変更をユーザーに知らせることができます。
以下のセレクタを使用して承認フローを選択します。
暗黙的フロー
ユーザーがいるときにブラウザ内で使用するアクセス トークンを取得します。
暗黙的フローの例は、Identity Services への移行前後のウェブアプリを示しています。
認可コードフロー
Google が発行したユーザーごとの認可コードがバックエンド プラットフォームに配信され、そこでアクセス トークンや更新トークンと交換されます。
認可コードフローの例は、Identity Services への移行前後のウェブアプリを示しています。
このガイド全体を通して、太字で示されている既存の機能を追加、削除、更新、または置換する手順を実施してください。
ブラウザ内ウェブアプリに対する変更
このセクションでは、Google Identity Services JavaScript ライブラリに移行する際に、ブラウザ内ウェブアプリに加える変更を確認します。
影響を受けるコードの特定とテスト
デバッグ Cookie を使用すると、影響を受けるコードを見つけて、非推奨になった後の動作をテストできます。
大規模アプリや複雑なアプリでは、gapi.auth2
モジュールのサポート終了によって影響を受けるすべてのコードを見つけることが難しい場合があります。サポートが終了する機能の既存の使用状況をコンソールに記録するには、G_AUTH2_MIGRATION
Cookie の値を informational
に設定します。必要に応じて、コロンとそれに続けて Key-Value を追加して、セッション ストレージにもログ記録します。ログイン後、認証情報を受け取ったら、収集したログを確認して、分析のためにバックエンドに送信します。たとえば、informational:showauth2use
は、オリジンと URL を showauth2use
という名前のセッション ストレージ キーに保存します。
gapi.auth2
モジュールが読み込まれなくなったときのアプリの動作を確認するには、G_AUTH2_MIGRATION
Cookie の値を enforced
に設定します。これにより、適用日より前に非推奨後の動作をテストできます。
有効な G_AUTH2_MIGRATION
Cookie 値:
enforced
gapi.auth2
モジュールをロードしないでください。informational
非推奨となった機能の使用状況を JS コンソールに記録します。また、オプションのキー名が設定されている場合は、セッション ストレージにログを記録します(informational:key-name
)。
ユーザーへの影響を最小限に抑えるため、本番環境で使用する前に、開発とテストの際にこの Cookie をローカルに設定することをおすすめします。
ライブラリとモジュール
gapi.auth2
モジュールは、ログインのユーザー認証と認可の暗黙的フローを管理し、この非推奨モジュール、そのオブジェクトとメソッドを Google Identity Services ライブラリに置き換えます。
ドキュメントに Identity Services ライブラリを追加して、ウェブアプリに ID サービス ライブラリを追加します。
<script src="https://accounts.google.com/gsi/client" async defer></script>
gapi.load('auth2', function)
を使用して auth2
モジュールを読み込むインスタンスを削除します。
Google Identity Services ライブラリは、gapi.auth2
モジュールの使用に代わるものです。JavaScript 用 Google API クライアント ライブラリの gapi.client
モジュールを引き続き使用し、検出ドキュメントから呼び出し可能な JS メソッドの自動作成、複数の API 呼び出しのバッチ処理、CORS 管理機能を利用できます。
Cookie
ユーザー認証には Cookie の使用は必要ありません。
ユーザー認証で Cookie がどのように使用されるかについては、Google ログインからの移行をご覧ください。また、他の Google サービスで Cookie を使用する場合は、Google による Cookie の使用方法をご覧ください。
認証情報
Google Identity Services は、ユーザー認証と認可を 2 つの異なるオペレーションに分離します。ユーザー認証情報は、認可に使用されるアクセス トークンとは別に返されます。
これらの変更を表示するには、認証情報の例をご覧ください。
暗黙的フロー
ユーザー認証と認可を分離するには、認可フローからユーザー プロファイルの処理を削除します。
以下の Google ログイン JavaScript クライアント リファレンスを削除します。
Methods
GoogleUser.getBasicProfile()
GoogleUser.getId()
認可コードフロー
Identity Services は、ブラウザの認証情報を ID トークンとアクセス トークンに分離します。この変更は、バックエンド プラットフォームから Google OAuth 2.0 エンドポイントへの直接呼び出し、またはプラットフォーム上の安全なサーバー(Google API Node.js クライアントなど)で実行されているライブラリを介して取得した認証情報には適用されません。
セッション状態
以前は、Google ログインを使用して以下を使用してユーザーのログイン ステータスを管理できました。
- ユーザーのセッション状態をモニタリングするためのコールバック ハンドラ。
- ユーザーの Google アカウントのイベントとログイン ステータスの変更のリスナー。
ウェブアプリへのログイン状態とユーザー セッションの管理はユーザーの責任です。
以下の Google ログイン JavaScript クライアント リファレンスを削除します。
オブジェクト:
gapi.auth2.SignInOptions
メソッド:
GoogleAuth.attachClickHandler()
GoogleAuth.isSignedIn()
GoogleAuth.isSignedIn.get()
GoogleAuth.isSignedIn.listen()
GoogleAuth.signIn()
GoogleAuth.signOut()
GoogleAuth.currentUser.get()
GoogleAuth.currentUser.listen()
GoogleUser.isSignedIn()
クライアントの構成
ウェブアプリを更新して、暗黙的または認証のコードフローのトークン クライアントを初期化します。
以下の Google ログイン JavaScript クライアント リファレンスを削除します。
オブジェクト:
gapi.auth2.ClientConfig
gapi.auth2.OfflineAccessOptions
メソッド:
gapi.auth2.getAuthInstance()
GoogleUser.grant()
暗黙的フロー
トークン クライアントを初期化するの例に沿って、TokenClientConfig
オブジェクトと initTokenClient()
呼び出しを追加してウェブアプリを構成します。
Google ログイン JavaScript クライアント リファレンスを Google Identity Services に置き換えます。
オブジェクト:
TokenClientConfig
のあるgapi.auth2.AuthorizeConfig
メソッド:
google.accounts.oauth2.initTokenClient()
のあるgapi.auth2.init()
パラメータ:
gapi.auth2.AuthorizeConfig.login_hint
(TokenClientConfig.login_hint
を指定)gapi.auth2.GoogleUser.getHostedDomain()
(TokenClientConfig.hd
を指定)
認可コードフロー
コード クライアントを初期化するの例に沿って、CodeClientConfig
オブジェクトと initCodeClient()
呼び出しを追加してウェブアプリを構成します。
暗黙的フローから認可コードフローに切り替える場合:
削除 Google ログイン JavaScript クライアント リファレンス
オブジェクト:
gapi.auth2.AuthorizeConfig
メソッド:
gapi.auth2.init()
パラメータ:
gapi.auth2.AuthorizeConfig.login_hint
gapi.auth2.GoogleUser.getHostedDomain()
トークンのリクエスト
ボタンのクリックなどのユーザー ジェスチャーによって、暗黙的なフローでアクセス トークンがユーザーのブラウザに直接返されるか、またはユーザーごとの認証コードをアクセス トークンと更新トークンと交換した後にバックエンド プラットフォームに返されるリクエストが生成されます。
暗黙的フロー
ユーザーが Google にログインしていて、セッションがアクティブなときに、ブラウザでアクセス トークンを取得して使用できます。暗黙的モードの場合、以前にリクエストがあった場合でも、ユーザー トークンでアクセス トークンをリクエストする必要があります。
Google ログイン JavaScript クライアント リファレンスを Google Identity Services に置き換えます。
メソッド:
TokenClient.requestAccessToken()
のあるgapi.auth2.authorize()
TokenClient.requestAccessToken()
のあるGoogleUser.reloadAuthResponse()
リンクまたはボタンを追加すると、requestAccessToken()
を呼び出してポップアップ UX フローを開始してアクセス トークンをリクエストしたり、既存のトークンが期限切れになった場合に新しいトークンを取得したりできます。
更新:
requestAccessToken()
を使用して、OAuth 2.0 トークンフローをトリガーします。requestAccessToken
とOverridableTokenClientConfig
を使用して、多くのスコープに対する 1 つのリクエストを複数の小さなリクエストに分割することで、段階的な認可をサポートします。- 既存のトークンが期限切れになるか取り消されたら、新しいトークンをリクエストします。
複数のスコープを扱う場合、スコープを一度に必要とせずに、スコープのみをリクエストするために、コードベースの構造を変更することが必要になる場合があります。これは、段階的な認可と呼ばれます。各リクエストには、できるだけ少ないスコープ(できるだけ 1 つのスコープ)を指定する必要があります。アプリを認可して増分認証を行う方法については、ユーザーの同意を処理する方法をご覧ください。
アクセス トークンが期限切れになると、gapi.auth2
モジュールは自動的にウェブアプリ用の新しい有効なアクセス トークンを取得します。ユーザーのセキュリティ向上のため、この自動トークン更新プロセスは、Google Identity Services ライブラリではサポートされていません。期限切れのアクセス トークンを検出して新しいアクセス トークンをリクエストするには、ウェブアプリを更新する必要があります。詳しくは、以下のトークン処理のセクションをご覧ください。
認可コードフロー
リンクまたはボタンを追加して、requestCode()
を呼び出し、Google に認証コードをリクエストします。例については、OAuth 2.0 コードフローをトリガーするをご覧ください。
期限切れまたは取り消し済みのアクセス トークンに応答する方法について詳しくは、以下のトークン処理のセクションをご覧ください。
トークンの処理
追加エラー処理を使用して、期限切れまたは取り消されたアクセス トークンが使用されたときに失敗した Google API 呼び出しを検出し、新しい有効なアクセス トークンをリクエストします。
期限切れまたは取り消されたアクセス トークンが使用されると、Google API によって HTTP ステータス コード 401 Unauthorized
および invalid_token
のエラー メッセージが返されます。例については、無効なトークン レスポンスをご覧ください。
トークンが期限切れの場合
アクセス トークンの有効期間は短く、多くの場合は数分間のみ有効です。
トークンの取り消し
Google アカウントの所有者は、以前付与された同意をいつでも取り消すことができます。この操作を行うと、既存のアクセス トークンと更新トークンが無効になります。取り消しは、revoke()
または Google アカウントを使用して、プラットフォームからトリガーされます。
Google ログイン JavaScript クライアント リファレンスを Google Identity Services に置き換えます。
メソッド:
google.accounts.oauth2.revoke()
のあるgetAuthInstance().disconnect()
google.accounts.oauth2.revoke()
のあるGoogleUser.disconnect()
ユーザーがプラットフォームで自分のアカウントを削除した場合、またはアプリでのデータ共有への同意を取り消す場合は、revoke
を呼び出します。
ユーザーの同意プロンプト
ウェブアプリまたはバックエンド プラットフォームのいずれかがアクセス トークンをリクエストすると、Google はユーザーに同意ダイアログを表示します。Google がユーザーに表示する同意ダイアログの例をご覧ください。
アプリにアクセス トークンを発行する前に、既存のアクティブな Google セッションで、ユーザーに同意を促し、結果を記録する必要があります。既存のセッションがまだ確立されていない場合は、Google アカウントへのログインを求められることがあります。
ユーザーのログイン
ユーザーは、別のブラウザタブで Google アカウントにログインするか、ブラウザやオペレーティング システムからネイティブにログインできます。Google でログインをサイトに追加して、ユーザーが最初にアプリを開いたときに Google アカウントとブラウザ間のアクティブ セッションを確立することをおすすめします。これにより、次のようなメリットが得られます。
- ユーザーがログインしなければならない回数を最小限に抑える。アクセス トークンをリクエストすると、アクティブなセッションが存在しない場合に Google アカウントのログイン プロセスが開始されます。
CodeClientConfig
オブジェクトまたはTokenClientConfig
オブジェクトのlogin_hint
パラメータの値として、JWT ID トークンの認証情報email
フィールドを直接使用します。これは、プラットフォームでユーザー アカウント管理システムを維持しない場合に特に便利です。- Google アカウントをプラットフォーム上の既存のローカル ユーザー アカウントを検索して関連付け、プラットフォーム上の重複アカウントを最小限に抑えることができます。
- 新しいローカル アカウントが作成されると、登録ダイアログとフローがユーザー認証ダイアログとフローから明確に分離されるため、必要なステップの数が減り、離脱率が向上します。
ログイン後、アクセス トークンが発行される前に、ユーザーはリクエストされたスコープについてアプリケーションに同意する必要があります。
トークンと同意レスポンス
ユーザーが同意すると、アクセス トークンが、ユーザーによって承認または拒否されたスコープのリストとともに返されます。
権限をきめ細かく設定することで、ユーザーは個々のスコープを承認または拒否できます。複数のスコープへのアクセスをリクエストすると、各スコープは他のスコープとは独立して許可または拒否されます。ユーザーの選択に基づいて、アプリは個々のスコープに依存する機能を選択的に有効にします。
暗黙的フロー
Google ログイン JavaScript クライアント リファレンスを Google Identity Services に置き換えます。
オブジェクト:
TokenClient.TokenResponse
のあるgapi.auth2.AuthorizeResponse
TokenClient.TokenResponse
のあるgapi.auth2.AuthResponse
メソッド:
google.accounts.oauth2.hasGrantedAllScopes()
のあるGoogleUser.hasGrantedScopes()
google.accounts.oauth2.hasGrantedAllScopes()
のあるGoogleUser.getGrantedScopes()
削除 Google ログイン JavaScript クライアント参照:
メソッド:
GoogleUser.getAuthResponse()
こちらのきめ細かい権限の例に沿って、hasGrantedAllScopes()
と hasGrantedAnyScope()
を使用してウェブアプリを更新します。
認可コードフロー
認証コードの処理の手順に沿って、認証コード エンドポイントをバックエンド プラットフォームに更新または追加します。
プラットフォームを更新して、コードモデルの使用ガイドに記載されている手順に沿ってリクエストを検証し、アクセス トークンと更新トークンを取得します。
プラットフォームを更新して、ユーザーが承認した個々のスコープに基づいて機能を選択的に有効または無効にします。手順については、段階的な認可とユーザーが付与するアクセス スコープの確認をご覧ください。
暗黙的フローの例
従来の方法
GAPI クライアント ライブラリ
ユーザーの同意に関するポップアップ ダイアログを使用してブラウザで実行されている JavaScript 用 Google API クライアント ライブラリの例。
gapi.auth2
モジュールは gapi.client.init()
によって自動的に読み込まれて使用されるため、非表示になっています。
<!DOCTYPE html>
<html>
<head>
<script src="https://apis.google.com/js/api.js"></script>
<script>
function start() {
gapi.client.init({
'apiKey': 'YOUR_API_KEY',
'clientId': 'YOUR_CLIENT_ID',
'scope': 'https://www.googleapis.com/auth/cloud-translation',
'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
}).then(function() {
// Execute an API request which is returned as a Promise.
// The method name language.translations.list comes from the API discovery.
return gapi.client.language.translations.list({
q: 'hello world',
source: 'en',
target: 'de',
});
}).then(function(response) {
console.log(response.result.data.translations[0].translatedText);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
};
// Load the JavaScript client library and invoke start afterwards.
gapi.load('client', start);
</script>
</head>
<body>
<div id="results"></div>
</body>
</html>
JS クライアント ライブラリ
ユーザーの同意のためにポップアップ ダイアログを使用し、ブラウザで実行されているクライアント側ウェブ アプリケーション用の OAuth 2.0。
gapi.auth2
モジュールは手動で読み込まれます。
<!DOCTYPE html>
<html><head></head><body>
<script>
var GoogleAuth;
var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
function handleClientLoad() {
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
}
function initClient() {
// In practice, your app can retrieve one or more discovery documents.
var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client.init({
'apiKey': 'YOUR_API_KEY',
'clientId': 'YOUR_CLIENT_ID',
'discoveryDocs': [discoveryUrl],
'scope': SCOPE
}).then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
var user = GoogleAuth.currentUser.get();
setSigninStatus();
// Call handleAuthClick function when user clicks on
// "Sign In/Authorize" button.
$('#sign-in-or-out-button').click(function() {
handleAuthClick();
});
$('#revoke-access-button').click(function() {
revokeAccess();
});
});
}
function handleAuthClick() {
if (GoogleAuth.isSignedIn.get()) {
// User is authorized and has clicked "Sign out" button.
GoogleAuth.signOut();
} else {
// User is not signed in. Start Google auth flow.
GoogleAuth.signIn();
}
}
function revokeAccess() {
GoogleAuth.disconnect();
}
function setSigninStatus() {
var user = GoogleAuth.currentUser.get();
var isAuthorized = user.hasGrantedScopes(SCOPE);
if (isAuthorized) {
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
$('#auth-status').html('You are currently signed in and have granted ' +
'access to this app.');
} else {
$('#sign-in-or-out-button').html('Sign In/Authorize');
$('#revoke-access-button').css('display', 'none');
$('#auth-status').html('You have not authorized this app or you are ' +
'signed out.');
}
}
function updateSigninStatus() {
setSigninStatus();
}
</script>
<button id="sign-in-or-out-button"
style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
style="display: none; margin-left: 25px">Revoke access</button>
<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
</body></html>
OAuth 2.0 エンドポイント
クライアントサイド ウェブ アプリケーション用の OAuth 2.0。ブラウザで動作し、ユーザーの同意用に Google へのリダイレクトを使用します。
この例では、Google の OAuth 2.0 エンドポイントをユーザーのブラウザから直接呼び出しています。gapi.auth2
モジュールや JavaScript ライブラリは使用していません。
<!DOCTYPE html>
<html><head></head><body>
<script>
var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
var fragmentString = location.hash.substring(1);
// Parse query string to see if page request is coming from OAuth 2.0 server.
var params = {};
var regex = /([^&=]+)=([^&]*)/g, m;
while (m = regex.exec(fragmentString)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
if (Object.keys(params).length > 0) {
localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
if (params['state'] && params['state'] == 'try_sample_request') {
trySampleRequest();
}
}
// If there's an access token, try an API request.
// Otherwise, start OAuth 2.0 flow.
function trySampleRequest() {
var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
if (params && params['access_token']) {
var xhr = new XMLHttpRequest();
xhr.open('GET',
'https://www.googleapis.com/drive/v3/about?fields=user&' +
'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response);
} else if (xhr.readyState === 4 && xhr.status === 401) {
// Token invalid, so prompt for user permission.
oauth2SignIn();
}
};
xhr.send(null);
} else {
oauth2SignIn();
}
}
/*
* Create form to request access token from Google's OAuth 2.0 server.
*/
function oauth2SignIn() {
// Google's OAuth 2.0 endpoint for requesting an access token
var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
// Create element to open OAuth 2.0 endpoint in new window.
var form = document.createElement('form');
form.setAttribute('method', 'GET'); // Send as a GET request.
form.setAttribute('action', oauth2Endpoint);
// Parameters to pass to OAuth 2.0 endpoint.
var params = {'client_id': YOUR_CLIENT_ID,
'redirect_uri': YOUR_REDIRECT_URI,
'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
'state': 'try_sample_request',
'include_granted_scopes': 'true',
'response_type': 'token'};
// Add form parameters as hidden input values.
for (var p in params) {
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', p);
input.setAttribute('value', params[p]);
form.appendChild(input);
}
// Add form to page and submit it to open the OAuth 2.0 endpoint.
document.body.appendChild(form);
form.submit();
}
</script>
<button onclick="trySampleRequest();">Try sample request</button>
</body></html>
新しい方法
GIS のみ
この例では、トークンモデルを使用した Google Identity Service JavaScript ライブラリと、ユーザーの同意に関するポップアップ ダイアログのみを示しています。クライアントの構成、アクセス トークンのリクエストと取得、Google API の呼び出しに必要な最小限の手順について説明します。
<!DOCTYPE html>
<html>
<head>
<script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
</head>
<body>
<script>
var client;
var access_token;
function initClient() {
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: (tokenResponse) => {
access_token = tokenResponse.access_token;
},
});
}
function getToken() {
client.requestAccessToken();
}
function revokeToken() {
google.accounts.oauth2.revoke(access_token, () => {console.log('access token revoked')});
}
function loadCalendar() {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.googleapis.com/calendar/v3/calendars/primary/events');
xhr.setRequestHeader('Authorization', 'Bearer ' + access_token);
xhr.send();
}
</script>
<h1>Google Identity Services Authorization Token model</h1>
<button onclick="getToken();">Get access token</button><br><br>
<button onclick="loadCalendar();">Load Calendar</button><br><br>
<button onclick="revokeToken();">Revoke token</button>
</body>
</html>
GAPI async/await
この例では、トークンモデルを使用して Google Identity Service ライブラリを追加し、gapi.auth2
モジュールを削除して、JavaScript 用 Google API クライアント ライブラリを使用して API を呼び出す方法を示しています。
Promise の async と await は、ライブラリの読み込み順序を適用し、承認エラーのキャッチと再試行に使用されます。API 呼び出しは、有効なアクセス トークンが使用可能になった後にのみ行われます。
ページが最初に読み込まれたとき、またはアクセス トークンの期限が切れた後にアクセス トークンがない場合、ユーザーは [カレンダーを表示] ボタンを押す必要があります。
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>GAPI with GIS async/await</h1>
<button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
<button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
<script>
const gapiLoadPromise = new Promise((resolve, reject) => {
gapiLoadOkay = resolve;
gapiLoadFail = reject;
});
const gisLoadPromise = new Promise((resolve, reject) => {
gisLoadOkay = resolve;
gisLoadFail = reject;
});
var tokenClient;
(async () => {
document.getElementById("showEventsBtn").style.visibility="hidden";
document.getElementById("revokeBtn").style.visibility="hidden";
// First, load and initialize the gapi.client
await gapiLoadPromise;
await new Promise((resolve, reject) => {
// NOTE: the 'auth2' module is no longer loaded.
gapi.load('client', {callback: resolve, onerror: reject});
});
await gapi.client.init({
// NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
})
.then(function() { // Load the Calendar API discovery document.
gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
});
// Now load the GIS client
await gisLoadPromise;
await new Promise((resolve, reject) => {
try {
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
prompt: 'consent',
callback: '', // defined at request time in await/promise scope.
});
resolve();
} catch (err) {
reject(err);
}
});
document.getElementById("showEventsBtn").style.visibility="visible";
document.getElementById("revokeBtn").style.visibility="visible";
})();
async function getToken(err) {
if (err.result.error.code == 401 || (err.result.error.code == 403) &&
(err.result.error.status == "PERMISSION_DENIED")) {
// The access token is missing, invalid, or expired, prompt for user consent to obtain one.
await new Promise((resolve, reject) => {
try {
// Settle this promise in the response callback for requestAccessToken()
tokenClient.callback = (resp) => {
if (resp.error !== undefined) {
reject(resp);
}
// GIS has automatically updated gapi.client with the newly issued access token.
console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));
resolve(resp);
};
tokenClient.requestAccessToken();
} catch (err) {
console.log(err)
}
});
} else {
// Errors unrelated to authorization: server errors, exceeding quota, bad requests, and so on.
throw new Error(err);
}
}
function showEvents() {
// Try to fetch a list of Calendar events. If a valid access token is needed,
// prompt to obtain one and then retry the original request.
gapi.client.calendar.events.list({ 'calendarId': 'primary' })
.then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
.catch(err => getToken(err)) // for authorization errors obtain an access token
.then(retry => gapi.client.calendar.events.list({ 'calendarId': 'primary' }))
.then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
.catch(err => console.log(err)); // cancelled by user, timeout, etc.
}
function revokeToken() {
let cred = gapi.client.getToken();
if (cred !== null) {
google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
gapi.client.setToken('');
}
}
</script>
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoadOkay()" onerror="gapiLoadFail(event)"></script>
<script async defer src="https://accounts.google.com/gsi/client" onload="gisLoadOkay()" onerror="gisLoadFail(event)"></script>
</body>
</html>
GAPI コールバック
この例では、トークンモデルを使用して Google Identity Service ライブラリを追加し、gapi.auth2
モジュールを削除して、JavaScript 用 Google API クライアント ライブラリを使用して API を呼び出す方法を示しています。
変数は、ライブラリの読み込み順序を適用するために使用されます。有効なアクセス トークンが返された後、コールバック内から GAPI 呼び出しが実行されます。
ユーザーは、ページが最初に読み込まれるときに [カレンダーを表示] ボタンを押し、カレンダー情報を更新するときに再度押す必要があります。
<!DOCTYPE html>
<html>
<head>
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
<script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
<h1>GAPI with GIS callbacks</h1>
<button id="showEventsBtn" onclick="showEvents();">Show Calendar</button><br><br>
<button id="revokeBtn" onclick="revokeToken();">Revoke access token</button>
<script>
let tokenClient;
let gapiInited;
let gisInited;
document.getElementById("showEventsBtn").style.visibility="hidden";
document.getElementById("revokeBtn").style.visibility="hidden";
function checkBeforeStart() {
if (gapiInited && gisInited){
// Start only when both gapi and gis are initialized.
document.getElementById("showEventsBtn").style.visibility="visible";
document.getElementById("revokeBtn").style.visibility="visible";
}
}
function gapiInit() {
gapi.client.init({
// NOTE: OAuth2 'scope' and 'client_id' parameters have moved to initTokenClient().
})
.then(function() { // Load the Calendar API discovery document.
gapi.client.load('https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest');
gapiInited = true;
checkBeforeStart();
});
}
function gapiLoad() {
gapi.load('client', gapiInit)
}
function gisInit() {
tokenClient = google.accounts.oauth2.initTokenClient({
client_id: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
callback: '', // defined at request time
});
gisInited = true;
checkBeforeStart();
}
function showEvents() {
tokenClient.callback = (resp) => {
if (resp.error !== undefined) {
throw(resp);
}
// GIS has automatically updated gapi.client with the newly issued access token.
console.log('gapi.client access token: ' + JSON.stringify(gapi.client.getToken()));
gapi.client.calendar.events.list({ 'calendarId': 'primary' })
.then(calendarAPIResponse => console.log(JSON.stringify(calendarAPIResponse)))
.catch(err => console.log(err));
document.getElementById("showEventsBtn").innerText = "Refresh Calendar";
}
// Conditionally ask users to select the Google Account they'd like to use,
// and explicitly obtain their consent to fetch their Calendar.
// NOTE: To request an access token a user gesture is necessary.
if (gapi.client.getToken() === null) {
// Prompt the user to select a Google Account and asked for consent to share their data
// when establishing a new session.
tokenClient.requestAccessToken({prompt: 'consent'});
} else {
// Skip display of account chooser and consent dialog for an existing session.
tokenClient.requestAccessToken({prompt: ''});
}
}
function revokeToken() {
let cred = gapi.client.getToken();
if (cred !== null) {
google.accounts.oauth2.revoke(cred.access_token, () => {console.log('Revoked: ' + cred.access_token)});
gapi.client.setToken('');
document.getElementById("showEventsBtn").innerText = "Show Calendar";
}
}
</script>
</body>
</html>
認可コードフローの例
Google Identity Service ライブラリのポップアップ UX では、URL リダイレクトを使用してバックエンド コード エンドポイントに認可コードを直接返すか、ユーザーのブラウザで実行中の JavaScript コールバック ハンドラにレスポンスを返します。いずれの場合も、バックエンド プラットフォームは OAuth 2.0 フローを完了して、有効な更新トークンとアクセス トークンを取得します。
従来の方法
サーバーサイド ウェブアプリ
バックエンド プラットフォームで実行されているサーバーサイド アプリの Google ログインを使用して、ユーザーの同意を得るために Google へのリダイレクトを使用する。
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>
<script>
function start() {
gapi.load('auth2', function() {
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID',
api_key: 'YOUR_API_KEY',
discovery_docs: ['https://www.googleapis.com/discovery/v1/apis/translate/v2/rest'],
// Scopes to request in addition to 'profile' and 'email'
scope: 'https://www.googleapis.com/auth/cloud-translation',
});
});
}
function signInCallback(authResult) {
if (authResult['code']) {
console.log("sending AJAX request");
// Send authorization code obtained from Google to backend platform
$.ajax({
type: 'POST',
url: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
// Always include an X-Requested-With header to protect against CSRF attacks.
headers: {
'X-Requested-With': 'XMLHttpRequest'
},
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
console.log(result);
},
processData: false,
data: authResult['code']
});
} else {
console.log('error: failed to obtain authorization code')
}
}
</script>
</head>
<body>
<button id="signinButton">Sign In With Google</button>
<script>
$('#signinButton').click(function() {
// Obtain an authorization code from Google
auth2.grantOfflineAccess().then(signInCallback);
});
</script>
</body>
</html>
リダイレクトを使用する HTTP/REST
ウェブサーバー アプリケーションに OAuth 2.0 を使用して、ユーザーのブラウザからバックエンド プラットフォームに認証コードを送信する。ユーザーの同意は、ユーザーのブラウザを Google にリダイレクトすることで処理されます。
/\*
\* Create form to request access token from Google's OAuth 2.0 server.
\*/
function oauthSignIn() {
// Google's OAuth 2.0 endpoint for requesting an access token
var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
// Create <form> element to submit parameters to OAuth 2.0 endpoint.
var form = document.createElement('form');
form.setAttribute('method', 'GET'); // Send as a GET request.
form.setAttribute('action', oauth2Endpoint);
// Parameters to pass to OAuth 2.0 endpoint.
var params = {'client\_id': 'YOUR_CLIENT_ID',
'redirect\_uri': 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URL',
'response\_type': 'token',
'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
'include\_granted\_scopes': 'true',
'state': 'pass-through value'};
// Add form parameters as hidden input values.
for (var p in params) {
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', p);
input.setAttribute('value', params[p]);
form.appendChild(input);
}
// Add form to page and submit it to open the OAuth 2.0 endpoint.
document.body.appendChild(form);
form.submit();
}
新しい方法
GIS ポップアップ UX
この例では、Google から認証コードを受け取るためのユーザーの同意ポリシーとコールバック ハンドラのポップアップ ダイアログを認証コードモデルを使用する Google Identity Service JavaScript ライブラリのみを示しています。クライアントの構成、同意の取得、認証コードをバックエンド プラットフォームに送信するために必要な最小限の手順について説明します。
<!DOCTYPE html>
<html>
<head>
<script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
</head>
<body>
<script>
var client;
function initClient() {
client = google.accounts.oauth2.initCodeClient({
client_id: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
ux_mode: 'popup',
callback: (response) => {
var code_receiver_uri = 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI',
// Send auth code to your backend platform
const xhr = new XMLHttpRequest();
xhr.open('POST', code_receiver_uri, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onload = function() {
console.log('Signed in as: ' + xhr.responseText);
};
xhr.send('code=' + response.code);
// After receipt, the code is exchanged for an access token and
// refresh token, and the platform then updates this web app
// running in user's browser with the requested calendar info.
},
});
}
function getAuthCode() {
// Request authorization code and obtain user consent
client.requestCode();
}
</script>
<button onclick="getAuthCode();">Load Your Calendar</button>
</body>
</html>
GIS リダイレクト UX
認証コードモデルは、ポップアップとリダイレクトの UX モードをサポートしており、プラットフォームごとにホストされているエンドポイントにユーザーごとの認証コードを送信できます。リダイレクト UX モードは次のとおりです。
<!DOCTYPE html>
<html>
<head>
<script src="https://accounts.google.com/gsi/client" onload="initClient()" async defer></script>
</head>
<body>
<script>
var client;
function initClient() {
client = google.accounts.oauth2.initCodeClient({
client_id: 'YOUR_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly \
https://www.googleapis.com/auth/photoslibrary.readonly',
ux_mode: 'redirect',
redirect_uri: 'YOUR_AUTHORIZATION_CODE_ENDPOINT_URI'
});
}
// Request an access token
function getAuthCode() {
// Request authorization code and obtain user consent
client.requestCode();
}
</script>
<button onclick="getAuthCode();">Load Your Calendar</button>
</body>
</html>
JavaScript ライブラリ
Google Identity Services は、複数の異なるライブラリとモジュールに存在する機能を統合し、置き換える、ユーザー認証と認可に使用される単一の JavaScript ライブラリです。
Identity Services への移行時に行うこと:
既存の JS ライブラリ | 新しい JS ライブラリ | メモ |
---|---|---|
apis.google.com/js/api.js |
accounts.google.com/gsi/client |
新しいライブラリを追加し、暗黙的なフローに従います。 |
apis.google.com/js/client.js |
accounts.google.com/gsi/client |
新しいライブラリと認証コードフローを追加する。 |
ライブラリ クイック リファレンス
古い Google ログインの JavaScript クライアント ライブラリと、新しい Google Identity Services ライブラリのオブジェクトとメソッドの比較。追加情報と移行中に行うべき操作が記載されています。
旧 | 新規 | メモ |
---|---|---|
GoogleAuth オブジェクトと関連メソッド: | ||
GoogleAuth.attachClickHandler() | 削除 | |
GoogleAuth.currentUser.get() | 削除 | |
GoogleAuth.currentUser.listen() | 削除 | |
GoogleAuth.disconnect() | google.accounts.oauth2.revoke | 「新」に置き換えます。https://myaccount.google.com/permissions から取り消しが行われる場合もあります |
GoogleAuth.grantOfflineAccess() を使用する | 削除したら、認可コードフローに沿って対応します。 | |
GoogleAuth.isSignedIn.get() | 削除 | |
GoogleAuth.isSignedIn.listen() | 削除 | |
GoogleAuth.signIn() | 削除 | |
GoogleAuth.signOut() | 削除 | |
GoogleAuth.then() | 削除 | |
GoogleUser オブジェクトと関連メソッド: | ||
GoogleUser.disconnect() | google.accounts.id.revoke | 「新」に置き換えます。https://myaccount.google.com/permissions から取り消しが行われる場合もあります |
GoogleUser.getAuthResponse() | requestCode() または requestAccessToken() | 古いものから新しいものに置き換える |
GoogleUser.getBasicProfile() | 削除ID トークンを使用する場合は、Google ログインからの移行をご覧ください。 | |
GoogleUser.getGrantedScopes() | hasGrantedAnyScope() | 古いものから新しいものに置き換える |
GoogleUser.getHostedDomain() | 削除 | |
GoogleUser.getId() | 削除 | |
GoogleUser.grantOfflineAccess() | 削除したら、認可コードフローに沿って対応します。 | |
GoogleUser.grant() を渡す | 削除 | |
GoogleUser.hasGrantedScopes() | hasGrantedAnyScope() | 古いものから新しいものに置き換える |
GoogleUser.isSignedIn() | 削除 | |
GoogleUser.reloadAuthResponse() | requestAccessToken() | 古いものを削除し、新しく呼び出して、期限切れまたは取り消し済みのアクセス トークンを置き換えます。 |
gapi.auth2 オブジェクトと関連メソッド: | ||
gapi.auth2.AuthorizeConfig オブジェクト | TokenClientConfig または CodeClientConfig | 古いものから新しいものに置き換える |
gapi.auth2.AuthorizeResponse オブジェクト | 削除 | |
gapi.auth2.AuthResponse オブジェクト | 削除 | |
gapi.auth2.authorization() | requestCode() または requestAccessToken() | 古いものから新しいものに置き換える |
gapi.auth2.ClientConfig() | TokenClientConfig または CodeClientConfig | 古いものから新しいものに置き換える |
gapi.auth2.getAuthInstance() | 削除 | |
gapi.auth2.init() | initTokenClient() または initCodeClient() | 古いものから新しいものに置き換える |
gapi.auth2.OfflineAccessOptions オブジェクト | 削除 | |
gapi.auth2.SignInOptions オブジェクト | 削除 | |
gapi.signin2 オブジェクトと関連メソッド: | ||
gapi.signin2.render() | 削除g_id_signin 要素や、google.accounts.id.renderButton に対する JS 呼び出しを HTML DOM で読み込むと、ユーザーの Google アカウントへのログインがトリガーされます。 |
認証情報の例
既存の認証情報
Google ログイン プラットフォーム ライブラリ、JavaScript 用 Google API クライアント ライブラリ、または Google Auth 2.0 エンドポイントへの直接呼び出しは、OAuth 2.0 アクセス トークンと OpenID Connect ID トークンの両方を 1 つのレスポンスで返します。
access_token
と id_token
の両方を含むレスポンスの例:
{
"token_type": "Bearer",
"access_token": "ya29.A0ARrdaM-SmArZaCIh68qXsZSzyeU-8mxhQERHrP2EXtxpUuZ-3oW8IW7a6D2J6lRnZrRj8S6-ZcIl5XVEqnqxq5fuMeDDH_6MZgQ5dgP7moY-yTiKR5kdPm-LkuPM-mOtUsylWPd1wpRmvw_AGOZ1UUCa6UD5Hg",
"scope": "https://www.googleapis.com/auth/calendar.readonly",
"login_hint": "AJDLj6I2d1RH77cgpe__DdEree1zxHjZJr4Q7yOisoumTZUmo5W2ZmVFHyAomUYzLkrluG-hqt4RnNxrPhArd5y6p8kzO0t8xIfMAe6yhztt6v2E-_Bb4Ec3GLFKikHSXNh5bI-gPrsI",
"expires_in": 3599,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjkzNDFhYmM0MDkyYjZmYzAzOGU0MDNjOTEwMjJkZDNlNDQ1MzliNTYiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiYXVkIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTE3NzI2NDMxNjUxOTQzNjk4NjAwIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkJBSW55TjN2MS1ZejNLQnJUMVo0ckEiLCJuYW1lIjoiQnJpYW4gRGF1Z2hlcnR5IiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hLS9BT2gxNEdnenAyTXNGRGZvbVdMX3VDemRYUWNzeVM3ZGtxTE5ybk90S0QzVXNRPXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkJyaWFuIiwiZmFtaWx5X25hbWUiOiJEYXVnaGVydHkiLCJsb2NhbGUiOiJlbiIsImlhdCI6MTYzODk5MTYzOCwiZXhwIjoxNjM4OTk1MjM4LCJqdGkiOiI5YmRkZjE1YWFiNzE2ZDhjYmJmNDYwMmM1YWM3YzViN2VhMDQ5OTA5In0.K3EA-3Adw5HA7O8nJVCsX1HmGWxWzYk3P7ViVBb4H4BoT2-HIgxKlx1mi6jSxIUJGEekjw9MC-nL1B9Asgv1vXTMgoGaNna0UoEHYitySI23E5jaMkExkTSLtxI-ih2tJrA2ggfA9Ekj-JFiMc6MuJnwcfBTlsYWRcZOYVw3QpdTZ_VYfhUu-yERAElZCjaAyEXLtVQegRe-ymScra3r9S92TA33ylMb3WDTlfmDpWL0CDdDzby2asXYpl6GQ7SdSj64s49Yw6mdGELZn5WoJqG7Zr2KwIGXJuSxEo-wGbzxNK-mKAiABcFpYP4KHPEUgYyz3n9Vqn2Tfrgp-g65BQ",
"session_state": {
"extraQueryParams": {
"authuser": "0"
}
},
"first_issued_at": 1638991637982,
"expires_at": 1638995236982,
"idpId": "google"
}
Google Identity Services 認証情報
Google Identity Services ライブラリは次のものを返します。
- アクセス トークンを取得します。
{
"access_token": "ya29.A0ARrdaM_LWSO-uckLj7IJVNSfnUityT0Xj-UCCrGxFQdxmLiWuAosnAKMVQ2Z0LLqeZdeJii3TgULp6hR_PJxnInBOl8UoUwWoqsrGQ7-swxgy97E8_hnzfhrOWyQBmH6zs0_sUCzwzhEr_FAVqf92sZZHphr0g",
"token_type": "Bearer",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/calendar.readonly"
}
- ID トークンを使用する場合。
{
"clientId": "538344653255-758c5h5isc45vgk27d8h8deabovpg6to.apps.googleusercontent.com",
"credential": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxODkyZWI0OWQ3ZWY5YWRmOGIyZTE0YzA1Y2EwZDAzMjcxNGEyMzciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2MzkxNTcyNjQsImF1ZCI6IjUzODM0NDY1MzI1NS03NThjNWg1aXNjNDV2Z2syN2Q4aDhkZWFib3ZwZzZ0by5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExNzcyNjQzMTY1MTk0MzY5ODYwMCIsIm5vbmNlIjoiZm9vYmFyIiwiaGQiOiJnb29nbGUuY29tIiwiZW1haWwiOiJkYWJyaWFuQGdvb2dsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiNTM4MzQ0NjUzMjU1LTc1OGM1aDVpc2M0NXZnazI3ZDhoOGRlYWJvdnBnNnRvLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkJyaWFuIERhdWdoZXJ0eSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vYS0vQU9oMTRHZ3pwMk1zRkRmb21XTF91Q3pkWFFjc3lTN2RrcUxOcm5PdEtEM1VzUT1zOTYtYyIsImdpdmVuX25hbWUiOiJCcmlhbiIsImZhbWlseV9uYW1lIjoiRGF1Z2hlcnR5IiwiaWF0IjoxNjM5MTU3NTY0LCJleHAiOjE2MzkxNjExNjQsImp0aSI6IjRiOTVkYjAyZjU4NDczMmUxZGJkOTY2NWJiMWYzY2VhYzgyMmI0NjUifQ.Cr-AgMsLFeLurnqyGpw0hSomjOCU4S3cU669Hyi4VsbqnAV11zc_z73o6ahe9Nqc26kPVCNRGSqYrDZPfRyTnV6g1PIgc4Zvl-JBuy6O9HhClAK1HhMwh1FpgeYwXqrng1tifmuotuLQnZAiQJM73Gl-J_6s86Buo_1AIx5YAKCucYDUYYdXBIHLxrbALsA5W6pZCqqkMbqpTWteix-G5Q5T8LNsfqIu_uMBUGceqZWFJALhS9ieaDqoxhIqpx_89QAr1YlGu_UO6R6FYl0wDT-nzjyeF5tonSs3FHN0iNIiR3AMOHZu7KUwZaUdHg4eYkU-sQ01QNY_11keHROCRQ",
"select_by": "user"
}
無効なトークン レスポンスです
期限切れ、取り消し済み、または無効なアクセス トークンを使用して API リクエストを実行しようとしたときの Google からのレスポンスの例:
HTTP レスポンス ヘッダー
www-authenticate: Bearer realm="https://accounts.google.com/", error="invalid_token"
レスポンスの本文
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Invalid Credentials",
"domain": "global",
"reason": "authError",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED"
}
}