このドキュメントでは、ウェブサーバー アプリケーションが Google API クライアント ライブラリまたは Google OAuth 2.0 エンドポイントを使用して、Google API にアクセスするための OAuth 2.0 認証を実装する方法について説明します。
OAuth 2.0 を使用すると、ユーザー名やパスワードなどの情報を非公開にしたまま、特定のデータをアプリケーションと共有できます。たとえば、あるアプリケーションでは、OAuth 2.0 を使用して、ユーザーから Google ドライブにファイルを保存する権限を取得できます。
この OAuth 2.0 のフローは、ユーザー認証に関するものです。これは、機密情報を保存し、状態を維持できるアプリケーション向けに設計されています。適切に認証されたウェブサーバー アプリケーションは、ユーザーがアプリケーションとやり取りするときや、ユーザーがアプリケーションを離れた後に API にアクセスできます。
ウェブサーバー アプリケーションは多くの場合、 サービス アカウントを使用して API リクエストを承認します。特に、ユーザー固有のデータではなくプロジェクト ベースのデータにアクセスするために Cloud API を呼び出す場合です。ウェブサーバー アプリケーションは、ユーザー承認と組み合わせてサービス アカウントを使用できます。
クライアント ライブラリ
このページの言語固有の例では、Google API クライアント ライブラリを使用して OAuth 2.0 認証を実装しています。コードサンプルを実行するには、まず使用言語のクライアント ライブラリをインストールする必要があります。
Google API クライアント ライブラリを使用してアプリケーションの OAuth 2.0 フローを処理すると、クライアント ライブラリで多数の処理が行われますが、通常、これらの操作は単独で処理する必要があります。たとえば、アプリが保存されたアクセス トークンを使用または更新できるタイミングや、アプリが同意を再取得する必要があるタイミングを決定します。また、正しいリダイレクト URL を生成し、認証コードをアクセス トークンと交換するリダイレクト ハンドラの実装をサポートします。
サーバーサイド アプリケーション用の Google API クライアント ライブラリは、次の言語で利用できます。
Prerequisites
プロジェクトでAPI を有効にする
Google API を呼び出すアプリケーションでは、 API Consoleで API を有効にする必要があります。
プロジェクトで API を有効にするには:
- Google API ConsoleのOpen the API Library 。
- If prompted, select a project, or create a new one.
- API Library には、利用可能なすべての API がプロダクト ファミリーと人気度に応じて分類されて表示されます。有効にしたい API がリストで見当たらない場合は、検索してその API を探すか、属しているプロダクト ファミリーの [すべて表示] をクリックします。
- 有効にする API を選択し、[有効にする] ボタンをクリックします。
- If prompted, enable billing.
- If prompted, read and accept the API's Terms of Service.
承認認証情報を作成する
OAuth 2.0 を使用して Google API にアクセスするアプリケーションには、Google の OAuth 2.0 サーバーに対してアプリケーションを識別するための認証情報が必要です。次の手順では、プロジェクトの認証情報を作成する方法について説明します。アプリケーションはその認証情報を使用して、そのプロジェクトで有効にした API にアクセスできます。
- Go to the Credentials page.
- [認証情報を作成] > [OAuth クライアント ID] をクリックします。
- アプリケーションの種類として [ウェブ アプリケーション] を選択します。
- フォームに記入し、[作成] をクリックします。PHP、Java、Python、Ruby、.NET などの言語やフレームワークを使用するアプリケーションでは、承認済みのリダイレクト URI を指定する必要があります。リダイレクト URI は、OAuth 2.0 サーバーがレスポンスを送信できるエンドポイントです。これらのエンドポイントは、Google の検証ルールを遵守している必要があります。
テストでは、ローカルマシンを参照する URI を指定します(例:
http://localhost:8080
)。なお、このドキュメントの例では、すべてhttp://localhost:8080
をリダイレクト URI として使用します。アプリケーションがページの他のリソースに認証コードを公開しないように、アプリの認証エンドポイントを設計することをおすすめします。
認証情報を作成したら、 API Consoleから client_secret.json ファイルをダウンロードします。自分のアプリケーションだけがアクセスできる場所にファイルを安全に保管する。
アクセス スコープを特定する
スコープを使用すると、アプリケーションは必要なリソースへのアクセス権のみをリクエストできると同時に、ユーザーはアプリケーションに付与するアクセス権の量を制御できます。そのため、リクエストされたスコープの数とユーザーの同意を取得する可能性の間には、反比例する可能性があります。
OAuth 2.0 認証の実装を開始する前に、アプリがアクセスする必要があるスコープを特定することをおすすめします。
また、アプリケーションは、段階的な認可プロセスを介して認可スコープへのアクセスをリクエストすることを推奨します。このプロセスでは、コンテキスト内のユーザーデータへのアクセスをアプリケーションがリクエストします。アプリがリクエストするアクセス権が必要な理由をユーザーが簡単に確認できるようになります。
OAuth 2.0 API スコープのドキュメントには、Google API へのアクセスに使用できるスコープの完全なリストが記載されています。
言語固有の要件
このドキュメントのコードサンプルを実行するには、Google アカウント、インターネット、ウェブブラウザが必要です。API クライアント ライブラリのいずれかを使用している場合は、以下の言語固有の要件もご覧ください。
PHP
このドキュメントの PHP コードサンプルを実行するには、次のものが必要です。
- PHP 5.6 以降(コマンドライン インターフェース(CLI)と JSON 拡張機能がインストールされていること)
- Composer 依存関係管理ツール。
-
PHP 用 Google API クライアント ライブラリ:
composer require google/apiclient:^2.10
Python
このドキュメントの Python のコードサンプルを実行するには、次のものが必要です。
- Python 2.6 以降
- pip パッケージ管理ツール。
- Python 用 Google API クライアント ライブラリ:
pip install --upgrade google-api-python-client
- ユーザー認証用の
google-auth
、google-auth-oauthlib
、google-auth-httplib2
。pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
- Flask Python ウェブ アプリケーション フレームワーク。
pip install --upgrade flask
requests
HTTP ライブラリ。pip install --upgrade requests
Ruby
このドキュメントで Ruby コードサンプルを実行するには、次のものが必要です。
- Ruby 2.2.2 以降
-
Ruby 用 Google API クライアント ライブラリ:
gem install google-api-client
-
Sinatra Ruby ウェブ アプリケーション フレームワーク。
gem install sinatra
Node.js
このドキュメントで Node.js のコードサンプルを実行するには、次のものが必要です。
- メンテナンスの LTS、アクティブな LTS、Node.js の現在のリリース。
-
Google API Node.js クライアント:
npm install googleapis
HTTP/REST
ライブラリをインストールすることなく、OAuth 2.0 エンドポイントを直接呼び出すことができます。
OAuth 2.0 アクセス トークンの取得
次の手順は、ユーザーに代わって API リクエストを実行することをユーザーの同意を得て、アプリケーションが Google の OAuth 2.0 サーバーとやり取りする方法を示しています。アプリケーションで、ユーザー認証が必要な Google API リクエストを実行する前に、ユーザーの同意を得る必要があります。
この手順の概要は次のとおりです。
- アプリが必要とする権限を特定します。
- アプリケーションは、リクエストされた権限のリストとともにユーザーを Google にリダイレクトします。
- ユーザーは、アプリケーションに権限を付与するかどうかを判断します。
- アプリケーションは、ユーザーが選択した内容を検出します。
- ユーザーがリクエストされた権限を付与すると、アプリケーションは、ユーザーに代わって API リクエストを行うために必要なトークンを取得します。
ステップ 1: 認可パラメータを設定する
まず、承認リクエストを作成します。このリクエストでは、アプリケーションを識別するパラメータを設定して、アプリケーションへのユーザー権限の付与を定義します。
- OAuth 2.0 認証と認可に Google クライアント ライブラリを使用する場合は、これらのパラメータを定義するオブジェクトを作成して構成します。
- Google OAuth 2.0 エンドポイントを直接呼び出すと、URL が生成され、その URL にパラメータが設定されます。
以下のタブでは、ウェブサーバー アプリケーションでサポートされている認証パラメータを定義しています。言語固有の例では、クライアント ライブラリまたは認可ライブラリを使用して、これらのパラメータを設定するオブジェクトを構成する方法も示しています。
PHP
次のコード スニペットでは、承認リクエストのパラメータを定義する Google\Client()
オブジェクトを作成します。
このオブジェクトは、client_secret.json ファイルからの情報を使用してアプリケーションを識別します。(このファイルの詳細については、認証情報の作成をご覧ください)。このオブジェクトは、アプリケーションがアクセス権限をリクエストしているスコープと、アプリケーションの認証エンドポイントの URL も識別します。認証エンドポイントは Google の OAuth 2.0 サーバーからのレスポンスを処理します。最後に、このコードはオプションの access_type
パラメータと include_granted_scopes
パラメータを設定します。
たとえば、次のコードは、ユーザーの Google ドライブへの読み取り専用のオフライン アクセスをリクエストします。
$client = new Google\Client(); $client->setAuthConfig('client_secret.json'); $client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY); $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'); // offline access will give you both an access and refresh token so that // your app can refresh the access token without user interaction. $client->setAccessType('offline'); // Using "consent" ensures that your application always receives a refresh token. // If you are not using offline access, you can omit this. $client->setApprovalPrompt('consent'); $client->setIncludeGrantedScopes(true); // incremental auth
このリクエストでは次の情報を指定します。
パラメータ | |||||||
---|---|---|---|---|---|---|---|
client_id |
必須 アプリケーションのクライアント ID。この値は、 API Console Credentials pageで確認できます。 PHP で、 $client = new Google\Client(); $client->setAuthConfig('client_secret.json'); |
||||||
redirect_uri |
必須 ユーザーが承認フローを完了した後に API サーバーがユーザーをリダイレクトする場所を決定します。この値は、クライアントの API Console
Credentials pageで設定した OAuth 2.0 クライアントの承認済みのリダイレクト URI のいずれかと完全に一致する必要があります。この値が、指定された
PHP でこの値を設定するには、 $client->setRedirectUri('https://oauth2.example.com/code'); |
||||||
scope |
必須 アプリケーションがユーザーに代わってアクセスできるリソースを識別するためのスコープのスペース区切りリスト。これらの値により、Google がユーザーに表示する同意画面が表示されます。 スコープを使用すると、アプリケーションは必要なリソースへのアクセス権のみをリクエストできます。また、ユーザーはアプリケーションに付与するアクセス権の量を制御できます。したがって、要求されるスコープの数とユーザーの同意を取得する可能性の間には、逆の関係があります。 PHP でこの値を設定するには、 $client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY); 可能な限り、アプリケーションが状況に応じた認可スコープへのアクセスをリクエストすることをおすすめします。状況に応じてユーザーデータへのアクセスをリクエストすることで、段階的な認可によって、アプリケーションがリクエストするアクセス権を必要とする理由をユーザーが簡単に理解できるようになります。 |
||||||
access_type |
推奨
ユーザーがブラウザにいないときに、アプリケーションがアクセス トークンを更新できるかどうかを示します。有効なパラメータ値は、デフォルト値の ユーザーがブラウザにいないときにアプリケーションでアクセス トークンを更新する必要がある場合は、値を PHP でこの値を設定するには、 $client->setAccessType('offline'); |
||||||
state |
推奨
アプリケーションが承認リクエストと承認サーバーのレスポンスの間で状態を維持するために使用する文字列値を指定します。ユーザーがアプリのアクセス リクエストを同意または拒否した後、 このパラメータは、アプリ内の適切なリソースにユーザーを誘導する、ノンスを送信する、クロスサイト リクエスト フォージェリを軽減するなどの目的で使用できます。 PHP でこの値を設定するには、 $client->setState($sample_passthrough_value); |
||||||
include_granted_scopes |
省略可 アプリケーションが増分認可を使用して、コンテキスト内の追加スコープへのアクセスをリクエストできるようにします。このパラメータの値を PHP でこの値を設定するには、 $client->setIncludeGrantedScopes(true); |
||||||
login_hint |
省略可 アプリケーションが認証しようとしているユーザーを認識している場合、このパラメータを使用して Google 認証サーバーにヒントを提供できます。サーバーはこのヒントを使用して、ログイン フォームにメールのフィールドに入力するか、適切なマルチログイン セッションを選択することで、ログインフローを簡素化します。 パラメータ値をメールアドレスまたは PHP でこの値を設定するには、 $client->setLoginHint('None'); |
||||||
prompt |
省略可 ユーザーに提示するプロンプトのスペース区切りリスト。大文字と小文字が区別されます。このパラメータを指定しない場合、プロジェクトが初めてアクセスをリクエストしたときにのみプロンプトが表示されます。詳しくは、 再同意のプロンプトをご覧ください。 PHP でこの値を設定するには、 $client->setApprovalPrompt('consent'); 表示される値は次のとおりです。
|
Python
次のコード スニペットでは、google-auth-oauthlib.flow
モジュールを使用して認可リクエストを作成します。
このコードでは Flow
オブジェクトを構築します。このオブジェクトは、認証情報の作成後にダウンロードした client_secret.json ファイルの情報を使用してアプリケーションを識別します。このオブジェクトは、アプリケーションがアクセスをリクエストしているスコープとアプリケーションの認証エンドポイントの URL も識別します。認証エンドポイントは Google の OAuth 2.0 サーバーからのレスポンスを処理します。最後に、このコードはオプションの access_type
パラメータと include_granted_scopes
パラメータを設定します。
たとえば、次のコードは、ユーザーの Google ドライブへの読み取り専用のオフライン アクセスをリクエストします。
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/drive.metadata.readonly']) # Indicate where the API server will redirect the user after the user completes # the authorization flow. The redirect URI is required. The value must exactly # match one of the authorized redirect URIs for the OAuth 2.0 client, which you # configured in the API Console. If this value doesn't match an authorized URI, # you will get a 'redirect_uri_mismatch' error. flow.redirect_uri = 'https://www.example.com/oauth2callback' # Generate URL for request to Google's OAuth 2.0 server. # Use kwargs to set optional request parameters. authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
このリクエストでは次の情報を指定します。
パラメータ | |||||||
---|---|---|---|---|---|---|---|
client_id |
必須 アプリケーションのクライアント ID。この値は、 API Console Credentials pageで確認できます。 Python で flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly']) |
||||||
redirect_uri |
必須 ユーザーが承認フローを完了した後に API サーバーがユーザーをリダイレクトする場所を決定します。この値は、クライアントの API Console
Credentials pageで設定した OAuth 2.0 クライアントの承認済みのリダイレクト URI のいずれかと完全に一致する必要があります。この値が、指定された
Python でこの値を設定するには、 flow.redirect_uri = 'https://oauth2.example.com/code' |
||||||
scope |
必須 アプリケーションがユーザーに代わってアクセスできるリソースを識別するスコープのリスト。これらの値により、Google がユーザーに表示する同意画面が表示されます。 スコープを使用すると、アプリケーションは必要なリソースへのアクセス権のみをリクエストできます。また、ユーザーはアプリケーションに付与するアクセス権の量を制御できます。したがって、要求されるスコープの数とユーザーの同意を取得する可能性の間には、逆の関係があります。 Python では、 flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly']) 可能な限り、アプリケーションが状況に応じた認可スコープへのアクセスをリクエストすることをおすすめします。状況に応じてユーザーデータへのアクセスをリクエストすることで、段階的な認可によって、アプリケーションがリクエストするアクセス権を必要とする理由をユーザーが簡単に理解できるようになります。 |
||||||
access_type |
推奨
ユーザーがブラウザにいないときに、アプリケーションがアクセス トークンを更新できるかどうかを示します。有効なパラメータ値は、デフォルト値の ユーザーがブラウザにいないときにアプリケーションでアクセス トークンを更新する必要がある場合は、値を Python では、 authorization_url, state = flow.authorization_url( access_type='offline', include_granted_scopes='true') |
||||||
state |
推奨
アプリケーションが承認リクエストと承認サーバーのレスポンスの間で状態を維持するために使用する文字列値を指定します。ユーザーがアプリのアクセス リクエストを同意または拒否した後、 このパラメータは、アプリ内の適切なリソースにユーザーを誘導する、ノンスを送信する、クロスサイト リクエスト フォージェリを軽減するなどの目的で使用できます。 Python では、 authorization_url, state = flow.authorization_url( access_type='offline', state=sample_passthrough_value, include_granted_scopes='true') |
||||||
include_granted_scopes |
省略可 アプリケーションが増分認可を使用して、コンテキスト内の追加スコープへのアクセスをリクエストできるようにします。このパラメータの値を Python では、 authorization_url, state = flow.authorization_url( access_type='offline', include_granted_scopes='true') |
||||||
login_hint |
省略可 アプリケーションが認証しようとしているユーザーを認識している場合、このパラメータを使用して Google 認証サーバーにヒントを提供できます。サーバーはこのヒントを使用して、ログイン フォームにメールのフィールドに入力するか、適切なマルチログイン セッションを選択することで、ログインフローを簡素化します。 パラメータ値をメールアドレスまたは Python では、 authorization_url, state = flow.authorization_url( access_type='offline', login_hint='None', include_granted_scopes='true') |
||||||
prompt |
省略可 ユーザーに提示するプロンプトのスペース区切りリスト。大文字と小文字が区別されます。このパラメータを指定しない場合、プロジェクトが初めてアクセスをリクエストしたときにのみプロンプトが表示されます。詳しくは、 再同意のプロンプトをご覧ください。 Python では、 authorization_url, state = flow.authorization_url( access_type='offline', prompt='consent', include_granted_scopes='true') 表示される値は次のとおりです。
|
Ruby
作成した client_secrets.json ファイルを使用して、アプリケーションのクライアント オブジェクトを構成します。クライアント オブジェクトを構成するときは、アプリケーションがアクセスする必要があるスコープを、OAuth 2.0 サーバーからのレスポンスを処理するアプリケーションの認証エンドポイントの URL に指定します。
たとえば、次のコードは、ユーザーの Google ドライブへの読み取り専用のオフライン アクセスをリクエストします。
require 'google/apis/drive_v2' require 'google/api_client/client_secrets' client_secrets = Google::APIClient::ClientSecrets.load auth_client = client_secrets.to_authorization auth_client.update!( :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly', :redirect_uri => 'http://www.example.com/oauth2callback', :additional_parameters => { "access_type" => "offline", # offline access "include_granted_scopes" => "true" # incremental auth } )
アプリケーションは、このクライアント オブジェクトを使用して OAuth 2.0 のオペレーション(認証リクエスト URL の生成、HTTP リクエストへのアクセス トークンの適用など)を実行します。
Node.js
次のコード スニペットでは、承認リクエストのパラメータを定義する google.auth.OAuth2
オブジェクトを作成します。
このオブジェクトは、client_secret.json ファイルの情報を使用してアプリケーションを識別します。アクセス トークンの取得をユーザーに許可するには、同意ページにリダイレクトします。同意ページの URL を作成するには:
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 Drive activity. const scopes = [ 'https://www.googleapis.com/auth/drive.metadata.readonly' ]; // Generate a url that asks permissions for the Drive activity scope 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 a best practice. include_granted_scopes: true });
重要な注意事項 - refresh_token
は最初の承認時にのみ返されます。詳しくは、
こちらをご覧ください。
HTTP/REST
Google の OAuth 2.0 エンドポイントは https://accounts.google.com/o/oauth2/v2/auth
にあります。このエンドポイントには HTTPS 経由でのみアクセスできます。プレーン HTTP 接続は拒否されます。
Google の認可サーバーは、ウェブサーバー アプリケーションで次のクエリ文字列パラメータをサポートしています。
パラメータ | |||||||
---|---|---|---|---|---|---|---|
client_id |
必須 アプリケーションのクライアント ID。この値は、 API Console Credentials pageで確認できます。 |
||||||
redirect_uri |
必須 ユーザーが承認フローを完了した後に API サーバーがユーザーをリダイレクトする場所を決定します。この値は、クライアントの API Console
Credentials pageで設定した OAuth 2.0 クライアントの承認済みのリダイレクト URI のいずれかと完全に一致する必要があります。この値が、指定された
|
||||||
response_type |
必須 Google OAuth 2.0 エンドポイントが認証コードを返すかどうかを指定します。 ウェブサーバー アプリケーションの場合は、パラメータ値を |
||||||
scope |
必須 アプリケーションがユーザーに代わってアクセスできるリソースを識別するためのスコープのスペース区切りリスト。これらの値により、Google がユーザーに表示する同意画面が表示されます。 スコープを使用すると、アプリケーションは必要なリソースへのアクセス権のみをリクエストできます。また、ユーザーはアプリケーションに付与するアクセス権の量を制御できます。したがって、要求されるスコープの数とユーザーの同意を取得する可能性の間には、逆の関係があります。 可能な限り、アプリケーションが状況に応じた認可スコープへのアクセスをリクエストすることをおすすめします。状況に応じてユーザーデータへのアクセスをリクエストすることで、段階的な認可によって、アプリケーションがリクエストするアクセス権を必要とする理由をユーザーが簡単に理解できるようになります。 |
||||||
access_type |
推奨
ユーザーがブラウザにいないときに、アプリケーションがアクセス トークンを更新できるかどうかを示します。有効なパラメータ値は、デフォルト値の ユーザーがブラウザにいないときにアプリケーションでアクセス トークンを更新する必要がある場合は、値を |
||||||
state |
推奨
アプリケーションが承認リクエストと承認サーバーのレスポンスの間で状態を維持するために使用する文字列値を指定します。ユーザーがアプリのアクセス リクエストを同意または拒否した後、 このパラメータは、アプリ内の適切なリソースにユーザーを誘導する、ノンスを送信する、クロスサイト リクエスト フォージェリを軽減するなどの目的で使用できます。 |
||||||
include_granted_scopes |
省略可 アプリケーションが増分認可を使用して、コンテキスト内の追加スコープへのアクセスをリクエストできるようにします。このパラメータの値を |
||||||
login_hint |
省略可 アプリケーションが認証しようとしているユーザーを認識している場合、このパラメータを使用して Google 認証サーバーにヒントを提供できます。サーバーはこのヒントを使用して、ログイン フォームにメールのフィールドに入力するか、適切なマルチログイン セッションを選択することで、ログインフローを簡素化します。 パラメータ値をメールアドレスまたは |
||||||
prompt |
省略可 ユーザーに提示するプロンプトのスペース区切りリスト。大文字と小文字が区別されます。このパラメータを指定しない場合、プロジェクトが初めてアクセスをリクエストしたときにのみプロンプトが表示されます。詳しくは、 再同意のプロンプトをご覧ください。 表示される値は次のとおりです。
|
ステップ 2: Google の OAuth 2.0 サーバーにリダイレクトする
ユーザーを Google の OAuth 2.0 サーバーにリダイレクトして、認証と認可のプロセスを開始します。これは通常、アプリケーションが最初にユーザーのデータにアクセスする必要がある場合に発生します。段階的な認可の場合は、アプリがまだアクセス権がない追加のリソースに最初にアクセスする必要があるときにも、このステップが発生します。
PHP
- Google の OAuth 2.0 サーバーからアクセスをリクエストする URL を生成します。
$auth_url = $client->createAuthUrl();
- ユーザーを
$auth_url
にリダイレクトします。header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Python
次の例は、Flask ウェブ アプリケーション フレームワークを使用してユーザーを認可 URL にリダイレクトする方法を示しています。
return flask.redirect(authorization_url)
Ruby
- Google の OAuth 2.0 サーバーからアクセスをリクエストする URL を生成します:
auth_uri = auth_client.authorization_uri.to_s
- ユーザーを
auth_uri
にリダイレクトします。
Node.js
-
ステップ 1 の
generateAuthUrl
メソッドで生成された URLauthorizationUrl
を使用して、Google の OAuth 2.0 サーバーからアクセスをリクエストします。 -
ユーザーを
authorizationUrl
にリダイレクトします。res.writeHead(301, { "Location": authorizationUrl });
HTTP/REST
Sample redirect to Google's authorization server
An example URL is shown below, with line breaks and spaces for readability.
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=https%3A//oauth2.example.com/code& client_id=client_id
リクエスト URL を作成したら、ユーザーをその URL にリダイレクトします。
Google の OAuth 2.0 サーバーはユーザーを認証し、リクエストされたスコープにアプリケーションがアクセスすることを許可します。指定したリダイレクト URL を使用して、レスポンスがアプリケーションに返されます。
ステップ 3: Google が同意を求める
このステップでは、リクエストされたアクセス権をアプリケーションに付与するかどうかを決定します。この段階で、Google はアプリケーションの名前と、ユーザーの認証情報を使用してアクセスをリクエストする Google API サービス、および付与されるアクセス スコープを示す同意ウィンドウを表示します。ユーザーは、アプリケーションからリクエストされた 1 つ以上のスコープへのアクセス権を付与する、またはリクエストを拒否することに同意できます。
Google の OAuth 2.0 サーバーからのレスポンス(アクセスが許可されたかどうか)からのレスポンスを待機するため、この段階ではまだ何もする必要はありません。このレスポンスについては、次のステップで説明します。
エラー
Google の OAuth 2.0 認証エンドポイントへのリクエストでは、予想される認証および認可フローの代わりにユーザー向けのエラー メッセージが表示されることがあります。一般的なエラーコードと推奨される解決策を以下に示します。
admin_policy_enforced
Google Workspace 管理者のポリシーにより、リクエストされた 1 つ以上のスコープを Google アカウントが承認できません。OAuth クライアント ID にアクセス権が明示的に付与されるまで、すべてのスコープまたは機密性の高いスコープへのアクセスが制限される仕組みについて詳しくは、Google Workspace 管理者のヘルプ記事 「Google Workspace のデータにアクセスできるサードパーティ製アプリと内部アプリを制御する」をご覧ください。
disallowed_useragent
認証エンドポイントは、Google の OAuth 2.0 ポリシーで許可されていない埋め込みユーザー エージェント内に表示されています。
Android
Android デベロッパーは、android.webkit.WebView
で承認リクエストを開くと、このエラー メッセージを受け取ることがあります。代わりに、Android 向け Google ログインや OpenID Foundation の AppAuth for Android などの Android ライブラリを使用する必要があります。
このエラーは、Android アプリが埋め込みのユーザー エージェントで一般的なウェブリンクを開き、ユーザーがサイトから Google の OAuth 2.0 認証エンドポイントに移動したときに発生することがあります。デベロッパーは、Android App Links ハンドラまたはデフォルトのブラウザアプリの両方を含む、オペレーティング システムのデフォルトのリンク ハンドラで一般的なリンクを開くことができるようにする必要があります。Android カスタムタブ ライブラリもサポートされています。
iOS
iOS と macOS のデベロッパーは、WKWebView
で承認リクエストを開いたときにこのエラーが発生することがあります。代わりに、iOS 向け Google ログインや OpenID Foundation の iOS 向け AppAuth などの iOS ライブラリを使用する必要があります。
このエラーは、iOS アプリまたは macOS アプリが埋め込みユーザー エージェントで一般的なウェブリンクを開き、ユーザーがサイトから Google の OAuth 2.0 認証エンドポイントに移動したときに発生することがあります。デベロッパーは、Universal Links ハンドラまたはデフォルトのブラウザアプリの両方を含む、オペレーティング システムのデフォルトのリンクハンドラで一般的なリンクを開く必要があります。SFSafariViewController
ライブラリもサポートされているオプションです。
org_internal
リクエスト内の OAuth クライアント ID は、特定の Google Cloud 組織内の Google アカウントへのアクセスを制限するプロジェクトの一部です。この構成オプションの詳細については、OAuth 同意画面の設定に関するヘルプ記事のユーザータイプをご覧ください。
invalid_client
OAuth クライアント シークレットが正しくありません。このリクエストに使用されるクライアント ID とシークレットを含む OAuth クライアントの構成を確認します。
invalid_grant
アクセス トークンを更新する場合、または段階的認可を使用する場合、トークンが期限切れになっているか、無効化されている可能性があります。ユーザーを再度認証し、新しいトークンの取得についてユーザーの同意を得ます。このエラーが引き続き表示される場合は、アプリケーションが正しく構成されていることと、リクエストで正しいトークンとパラメータを使用していることを確認してください。それ以外の場合は、ユーザー アカウントが削除または無効化されている可能性があります。
redirect_uri_mismatch
承認リクエストで渡された redirect_uri
が、OAuth クライアント ID の承認済みのリダイレクト URI と一致しません。 Google API Console Credentials pageで承認済みのリダイレクト URI を確認してください。
redirect_uri
パラメータは、サポートが終了し、サポートされなくなった OAuth 帯域外(OOB)フローを参照する場合があります。統合を更新するには、移行ガイドをご覧ください。
ステップ 4: OAuth 2.0 サーバー レスポンスを処理する
OAuth 2.0 サーバーは、リクエストで指定された URL を使用してアプリケーションのアクセス リクエストに応答します。
ユーザーがアクセス リクエストを承認すると、レスポンスに認証コードが格納されます。ユーザーがリクエストを承認しないと、レスポンスにエラー メッセージが格納されます。ウェブサーバーに返される認証コードまたはエラー メッセージは、次に示すようにクエリ文字列に表示されます。
エラー レスポンス:
https://oauth2.example.com/auth?error=access_denied
認証コードのレスポンス:
https://oauth2.example.com/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
OAuth 2.0 サーバー レスポンスの例
次のサンプル URL をクリックすると、このフローをテストできます。サンプルでは、Google ドライブ内のファイルのメタデータを表示するための読み取り専用アクセス権がリクエストされます。
https://accounts.google.com/o/oauth2/v2/auth? scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly& access_type=offline& include_granted_scopes=true& response_type=code& state=state_parameter_passthrough_value& redirect_uri=https%3A//oauth2.example.com/code& client_id=client_id
OAuth 2.0 フローが完了すると、http://localhost/oauth2callback
にリダイレクトされます。ローカルマシンがそのアドレスでファイルを提供していないと、通常は 404 NOT FOUND
エラーが返されます。次のステップでは、ユーザーがアプリケーションに戻ったときに URI で返される情報について詳しく説明します。
ステップ 5: 認証コードを更新トークンとアクセス トークンに交換する
ウェブサーバーは、認証コードを受け取ると、その認証コードをアクセス トークンと交換できます。
PHP
認証コードをアクセス トークンと交換するには、authenticate
メソッドを使用します。
$client->authenticate($_GET['code']);
アクセス トークンは、getAccessToken
メソッドを使用して取得できます。
$access_token = $client->getAccessToken();
Python
コールバック ページで google-auth
ライブラリを使用して、承認サーバーのレスポンスを確認します。次に、flow.fetch_token
メソッドを使用して、レスポンスに含まれる認証コードをアクセス トークンと交換します。
state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'], state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) # Store the credentials in the session. # ACTION ITEM for developers: # Store user's access and refresh tokens in your data store if # incorporating this code into your real app. credentials = flow.credentials flask.session['credentials'] = { 'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'scopes': credentials.scopes}
Ruby
認証コードをアクセス トークンと交換するには、fetch_access_token!
メソッドを使用します。
auth_client.code = auth_code auth_client.fetch_access_token!
Node.js
認証コードをアクセス トークンと交換するには、getToken
メソッドを使用します。
const url = require('url'); // Receive the callback from Google's OAuth 2.0 server. if (req.url.startsWith('/oauth2callback')) { // Handle the OAuth 2.0 server response let q = url.parse(req.url, true).query; // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); }
HTTP/REST
認証コードをアクセス トークンと交換するには、https://oauth2.googleapis.com/token
エンドポイントを呼び出して、次のパラメータを設定します。
フィールド | |
---|---|
client_id |
Credentials pageから取得したクライアント ID。 API Console |
client_secret |
API Console Credentials pageから取得したクライアント シークレット。 |
code |
最初のリクエストから返された認証コード。 |
grant_type |
OAuth 2.0 仕様で定義されているように、このフィールドの値は authorization_code に設定する必要があります。 |
redirect_uri |
特定の client_id の API Console
Credentials page で、プロジェクトに対して指定されているリダイレクト URI の 1 つ。 |
次のスニペットは、リクエストの例を示しています。
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7& client_id=your_client_id& client_secret=your_client_secret& redirect_uri=https%3A//oauth2.example.com/code& grant_type=authorization_code
Google はこのリクエストに対して、有効期間の短いアクセス トークンと更新トークンを含む JSON オブジェクトを返します。
更新トークンは、Google の承認サーバーへの最初のリクエストで、アプリケーションが access_type
パラメータを offline
に設定した場合にのみ返されます。
レスポンスには、次のフィールドが含まれます。
フィールド | |
---|---|
access_token |
Google API リクエストの承認用にアプリケーションが送信するトークン。 |
expires_in |
アクセス トークンの残りの存続期間(秒単位)。 |
refresh_token |
新しいアクセス トークンの取得に使用できるトークン。更新トークンは、ユーザーがアクセス権を取り消すまで有効です。
このフィールドは、Google の承認サーバーへの最初のリクエストで access_type パラメータを offline に設定した場合にのみ、このレスポンスに含まれます。
|
scope |
access_token によって付与されるアクセスのスコープ。スペース区切りで、大文字と小文字が区別される文字列のリストとして表されます。 |
token_type |
返されるトークンのタイプ。現時点では、このフィールドの値は常に Bearer に設定されます。 |
次のスニペットは、レスポンスの例を示しています。
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "token_type": "Bearer", "scope": "https://www.googleapis.com/auth/drive.metadata.readonly", "refresh_token": "1//xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" }
エラー
アクセス トークンの認証コードを交換する際に、想定されるレスポンスではなく、次のエラーが発生することがあります。一般的なエラーコードと解決方法を以下に示します。
invalid_grant
指定された認証コードが無効であるか、形式が正しくありません。OAuth プロセスを再開して新しいコードをリクエストし、ユーザーに再度同意を促します。
Google API の呼び出し
PHP
アクセス トークンを使用して Google API を呼び出すには、次の手順を行います。
- 新しい
Google\Client
オブジェクトにアクセス トークンを適用する必要がある場合(たとえば、ユーザー セッションでアクセス トークンを保存した場合)は、setAccessToken
メソッドを使用します。$client->setAccessToken($access_token);
- 呼び出す API のサービス オブジェクトを作成します。サービス オブジェクトを作成するには、呼び出す API のコンストラクタに承認済み
Google\Client
オブジェクトを指定します。たとえば、Drive API を呼び出すには:$drive = new Google\Service\Drive($client);
- サービス オブジェクトによって提供されるインターフェースを使用して API サービスへのリクエストを行います。たとえば、認証されたユーザーの Google ドライブ内のファイルを一覧表示するには:
$files = $drive->files->listFiles(array())->getItems();
Python
アクセス トークンを取得したら、アプリケーションはそのトークンを使用して、特定のユーザー アカウントやサービス アカウントの代理として API リクエストを承認できます。ユーザー固有の承認認証情報を使用して、呼び出す API 用のサービス オブジェクトを構築し、そのオブジェクトを使用して承認済みの API リクエストを行います。
- 呼び出す API のサービス オブジェクトを作成します。サービス オブジェクトのビルドには、
googleapiclient.discovery
ライブラリのbuild
メソッドを呼び出して、API の名前とユーザー バージョン、ユーザー認証情報を指定します。たとえば、Drive API のバージョン 2 を呼び出すには、from googleapiclient.discovery import build drive = build('drive', 'v2', credentials=credentials)
を実行します。 - サービス オブジェクトによって提供されるインターフェースを使用して API サービスへのリクエストを行います。たとえば、認証されたユーザーの Google ドライブ内のファイルを一覧表示するには:
files = drive.files().list().execute()
Ruby
auth_client
オブジェクトを使用して Google API を呼び出すには、次の手順を行います。
- 呼び出す API のサービス オブジェクトを作成します。たとえば、Drive API のバージョン 2 を呼び出すには:
drive = Google::Apis::DriveV2::DriveService.new
- サービスに認証情報を設定します。
drive.authorization = auth_client
- サービス オブジェクトによって提供されるインターフェースを使用して API サービスへのリクエストを行います。たとえば、認証済みユーザーの Google ドライブ内のファイルの一覧を表示するには、次のようにします。
files = drive.list_files
または、メソッドに options
パラメータを指定して、メソッドごとに承認を指定することもできます。
files = drive.list_files(options: { authorization: auth_client })
Node.js
アクセス トークンを取得して OAuth2
オブジェクトに設定したら、そのオブジェクトを使用して Google API を呼び出します。アプリケーションは、特定のユーザー アカウントまたはサービス アカウントに代わって、このトークンを使用して API リクエストを承認できます。呼び出す API のサービス オブジェクトを作成します。
const { google } = require('googleapis'); // Example of using Google Drive API to list filenames in user's Drive. const drive = google.drive('v3'); drive.files.list({ auth: oauth2Client, pageSize: 10, fields: 'nextPageToken, files(id, name)', }, (err1, res1) => { if (err1) return console.log('The API returned an error: ' + err1); const files = res1.data.files; if (files.length) { console.log('Files:'); files.map((file) => { console.log(`${file.name} (${file.id})`); }); } else { console.log('No files found.'); } });
HTTP/REST
アプリケーションがアクセス トークンを取得した後、その API で必要なアクセス スコープが付与されている場合、特定のユーザー アカウントに代わって、このトークンを使用して Google API を呼び出すことができます。これを行うには、access_token
クエリ パラメータまたは Authorization
HTTP ヘッダー Bearer
値を指定して、API のリクエストにアクセス トークンを含めます。可能であれば、クエリ文字列はサーバーログに表示されるため、HTTP ヘッダーを使用することをおすすめします。ほとんどの場合、クライアント ライブラリを使用して Google API の呼び出しを設定できます(Drive Files API を呼び出すときなど)。
すべての Google API を試し、そのスコープは OAuth 2.0 Playground で確認できます。
HTTP GET の例
Authorization: Bearer
HTTP ヘッダーを使用した
drive.files
エンドポイント(Drive Files API)の呼び出しは次のようになります。独自のアクセス トークンを指定する必要があります。
GET /drive/v2/files HTTP/1.1 Host: www.googleapis.com Authorization: Bearer access_token
次に示すのは、access_token
クエリ文字列パラメータを使用した認証済みユーザーの同じ API の呼び出しです。
GET https://www.googleapis.com/drive/v2/files?access_token=access_token
curl
の例
これらのコマンドは、curl
コマンドライン アプリケーションでテストできます。HTTP ヘッダー オプション(推奨)を使用する例を次に示します。
curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files
または、クエリ文字列パラメータ オプションを使用します。
curl https://www.googleapis.com/drive/v2/files?access_token=access_token
サンプルコードの全文
次の例では、ユーザーが認証された後、アプリケーションがユーザーの Google ドライブのメタデータにアクセスすることに同意した後、ユーザーの Google ドライブ内のファイルを JSON 形式で出力します。
PHP
この例を実行するには:
- API Consoleで、ローカルマシンの URL をリダイレクト URL のリストに追加します。たとえば、
http://localhost:8080
を追加します。 - 新しいディレクトリを作成してそのディレクトリに移動します。例:
mkdir ~/php-oauth2-example cd ~/php-oauth2-example
- Composer を使用して、PHP 用の Google API クライアント ライブラリをインストールします。
composer require google/apiclient:^2.10
- 以下の内容で
index.php
ファイルとoauth2callback.php
ファイルを作成します。 - PHP を提供するように構成されたウェブサーバーでサンプルを実行します。PHP 5.6 以降を使用している場合は、PHP の組み込みテスト ウェブサーバー
php -S localhost:8080 ~/php-oauth2-example
を使用できます。
index.php
<?php require_once __DIR__.'/vendor/autoload.php'; session_start(); $client = new Google\Client(); $client->setAuthConfig('client_secrets.json'); $client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY); if (isset($_SESSION['access_token']) && $_SESSION['access_token']) { $client->setAccessToken($_SESSION['access_token']); $drive = new Google\Service\Drive($client); $files = $drive->files->listFiles(array())->getItems(); echo json_encode($files); } else { $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); }
oauth2callback.php
<?php require_once __DIR__.'/vendor/autoload.php'; session_start(); $client = new Google\Client(); $client->setAuthConfigFile('client_secrets.json'); $client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php'); $client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY); if (! isset($_GET['code'])) { $auth_url = $client->createAuthUrl(); header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); } else { $client->authenticate($_GET['code']); $_SESSION['access_token'] = $client->getAccessToken(); $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/'; header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL)); }
Python
この例では、Flask フレームワークを使用します。http://localhost:8080
でウェブ アプリケーションを実行し、OAuth 2.0 フローをテストできます。指定した URL に移動すると 4 つのリンクが表示されます。
- API リクエストをテストする: このリンクは、サンプル API リクエストを実行しようとしているページを指します。必要に応じて、承認フローが開始されます。成功すると、ページに API レスポンスが表示されます。
- 認証フローを直接テストします。このリンクは、承認フローを介してユーザーの送信を試行するページを指します。アプリが、ユーザーに代わって承認済みの API リクエストを送信する権限をリクエストします。
- 現在の認証情報を取り消す: このリンクは、ユーザーがすでにアプリケーションに付与している権限を 取り消すページを指します。
- Flask セッションの認証情報を消去: このリンクを使用すると、Flask セッションに保存されている認証情報が消去されます。これにより、すでにアプリに権限を付与しているユーザーが新しいセッションで API リクエストを実行しようとした場合、何が起きるのかがわかります。また、ユーザーがアプリに付与されている権限を取り消した場合でも、アプリが取り消したアクセス トークンでリクエストを承認しようとした場合に、アプリが受け取る API レスポンスを確認できます。
# -*- coding: utf-8 -*- import os import flask import requests import google.oauth2.credentials import google_auth_oauthlib.flow import googleapiclient.discovery # This variable specifies the name of a file that contains the OAuth 2.0 # information for this application, including its client_id and client_secret. CLIENT_SECRETS_FILE = "client_secret.json" # This OAuth 2.0 access scope allows for full read/write access to the # authenticated user's account and requires requests to use an SSL connection. SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly'] API_SERVICE_NAME = 'drive' API_VERSION = 'v2' app = flask.Flask(__name__) # Note: A secret key is included in the sample so that it works. # If you use this code in your application, replace this with a truly secret # key. See https://flask.palletsprojects.com/quickstart/#sessions. app.secret_key = 'REPLACE ME - this value is here as a placeholder.' @app.route('/') def index(): return print_index_table() @app.route('/test') def test_api_request(): if 'credentials' not in flask.session: return flask.redirect('authorize') # Load credentials from the session. credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) drive = googleapiclient.discovery.build( API_SERVICE_NAME, API_VERSION, credentials=credentials) files = drive.files().list().execute() # Save credentials back to session in case access token was refreshed. # ACTION ITEM: In a production app, you likely want to save these # credentials in a persistent database instead. flask.session['credentials'] = credentials_to_dict(credentials) return flask.jsonify(**files) @app.route('/authorize') def authorize(): # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps. flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES) # The URI created here must exactly match one of the authorized redirect URIs # for the OAuth 2.0 client, which you configured in the API Console. If this # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch' # error. flow.redirect_uri = flask.url_for('oauth2callback', _external=True) authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true') # Store the state so the callback can verify the auth server response. flask.session['state'] = state return flask.redirect(authorization_url) @app.route('/oauth2callback') def oauth2callback(): # Specify the state when creating the flow in the callback so that it can # verified in the authorization server response. state = flask.session['state'] flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( CLIENT_SECRETS_FILE, scopes=SCOPES, state=state) flow.redirect_uri = flask.url_for('oauth2callback', _external=True) # Use the authorization server's response to fetch the OAuth 2.0 tokens. authorization_response = flask.request.url flow.fetch_token(authorization_response=authorization_response) # Store credentials in the session. # ACTION ITEM: In a production app, you likely want to save these # credentials in a persistent database instead. credentials = flow.credentials flask.session['credentials'] = credentials_to_dict(credentials) return flask.redirect(flask.url_for('test_api_request')) @app.route('/revoke') def revoke(): if 'credentials' not in flask.session: return ('You need to <a href="/authorize">authorize</a> before ' + 'testing the code to revoke credentials.') credentials = google.oauth2.credentials.Credentials( **flask.session['credentials']) revoke = requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'}) status_code = getattr(revoke, 'status_code') if status_code == 200: return('Credentials successfully revoked.' + print_index_table()) else: return('An error occurred.' + print_index_table()) @app.route('/clear') def clear_credentials(): if 'credentials' in flask.session: del flask.session['credentials'] return ('Credentials have been cleared.<br><br>' + print_index_table()) def credentials_to_dict(credentials): return {'token': credentials.token, 'refresh_token': credentials.refresh_token, 'token_uri': credentials.token_uri, 'client_id': credentials.client_id, 'client_secret': credentials.client_secret, 'scopes': credentials.scopes} def print_index_table(): return ('<table>' + '<tr><td><a href="/test">Test an API request</a></td>' + '<td>Submit an API request and see a formatted JSON response. ' + ' Go through the authorization flow if there are no stored ' + ' credentials for the user.</td></tr>' + '<tr><td><a href="/authorize">Test the auth flow directly</a></td>' + '<td>Go directly to the authorization flow. If there are stored ' + ' credentials, you still might not be prompted to reauthorize ' + ' the application.</td></tr>' + '<tr><td><a href="/revoke">Revoke current credentials</a></td>' + '<td>Revoke the access token associated with the current user ' + ' session. After revoking credentials, if you go to the test ' + ' page, you should see an <code>invalid_grant</code> error.' + '</td></tr>' + '<tr><td><a href="/clear">Clear Flask session credentials</a></td>' + '<td>Clear the access token currently stored in the user session. ' + ' After clearing the token, if you <a href="/test">test the ' + ' API request</a> again, you should go back to the auth flow.' + '</td></tr></table>') if __name__ == '__main__': # When running locally, disable OAuthlib's HTTPs verification. # ACTION ITEM for developers: # When running in production *do not* leave this option enabled. os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # Specify a hostname and port that are set as a valid redirect URI # for your API project in the Google API Console. app.run('localhost', 8080, debug=True)
Ruby
この例では、Sinatra フレームワークを使用します。
require 'google/apis/drive_v2' require 'google/api_client/client_secrets' require 'json' require 'sinatra' enable :sessions set :session_secret, 'setme' get '/' do unless session.has_key?(:credentials) redirect to('/oauth2callback') end client_opts = JSON.parse(session[:credentials]) auth_client = Signet::OAuth2::Client.new(client_opts) drive = Google::Apis::DriveV2::DriveService.new files = drive.list_files(options: { authorization: auth_client }) "<pre>#{JSON.pretty_generate(files.to_h)}</pre>" end get '/oauth2callback' do client_secrets = Google::APIClient::ClientSecrets.load auth_client = client_secrets.to_authorization auth_client.update!( :scope => 'https://www.googleapis.com/auth/drive.metadata.readonly', :redirect_uri => url('/oauth2callback')) if request['code'] == nil auth_uri = auth_client.authorization_uri.to_s redirect to(auth_uri) else auth_client.code = request['code'] auth_client.fetch_access_token! auth_client.client_secret = nil session[:credentials] = auth_client.to_json redirect to('/') end end
Node.js
この例を実行するには:
-
API Consoleで、ローカルマシンの URL をリダイレクト URL のリストに追加します。たとえば、
http://localhost
を追加します。 - メンテナンスの LTS、アクティブな LTS、または現在のリリースの Node.js がインストールされていることを確認します。
-
新しいディレクトリを作成してそのディレクトリに移動します。例:
mkdir ~/nodejs-oauth2-example cd ~/nodejs-oauth2-example
-
Install the
Google API Client
Library
for Node.js using npm:
npm install googleapis
-
以下の内容で
main.js
ファイルを作成します。 -
サンプルを実行します。
node .\main.js
main.js
const http = require('http'); const https = require('https'); const url = require('url'); const { google } = require('googleapis'); /** * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI. * 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 Drive activity. const scopes = [ 'https://www.googleapis.com/auth/drive.metadata.readonly' ]; // Generate a url that asks permissions for the Drive activity scope 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 a best practice. include_granted_scopes: true }); /* Global variable that stores user credential in this code example. * ACTION ITEM for developers: * Store user's refresh token in your data store if * incorporating this code into your real app. * For more information on handling refresh tokens, * see https://github.com/googleapis/google-api-nodejs-client#handling-refresh-tokens */ let userCredential = null; async function main() { const server = http.createServer(async function (req, res) { // Example on redirecting user to Google's OAuth 2.0 server. if (req.url == '/') { res.writeHead(301, { "Location": authorizationUrl }); } // Receive the callback from Google's OAuth 2.0 server. if (req.url.startsWith('/oauth2callback')) { // Handle the OAuth 2.0 server response let q = url.parse(req.url, true).query; if (q.error) { // An error response e.g. error=access_denied console.log('Error:' + q.error); } else { // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); /** Save credential to the global variable in case access token was refreshed. * ACTION ITEM: In a production app, you likely want to save the refresh token * in a secure persistent database instead. */ userCredential = tokens; // Example of using Google Drive API to list filenames in user's Drive. const drive = google.drive('v3'); drive.files.list({ auth: oauth2Client, pageSize: 10, fields: 'nextPageToken, files(id, name)', }, (err1, res1) => { if (err1) return console.log('The API returned an error: ' + err1); const files = res1.data.files; if (files.length) { console.log('Files:'); files.map((file) => { console.log(`${file.name} (${file.id})`); }); } else { console.log('No files found.'); } }); } } // Example on revoking a token if (req.url == '/revoke') { // Build the string for the POST request let postData = "token=" + userCredential.access_token; // Options for POST request to Google's OAuth 2.0 server to revoke a token let postOptions = { host: 'oauth2.googleapis.com', port: '443', path: '/revoke', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; // Set up the request const postReq = https.request(postOptions, function (res) { res.setEncoding('utf8'); res.on('data', d => { console.log('Response: ' + d); }); }); postReq.on('error', error => { console.log(error) }); // Post the request with data postReq.write(postData); postReq.end(); } res.end(); }).listen(80); } main().catch(console.error);
HTTP/REST
この Python の例では、Flask フレームワークと Requests ライブラリを使用して OAuth 2.0 ウェブフローのデモを行います。このフローには Python 用 Google API クライアント ライブラリを使用することをおすすめします。(Python タブの例ではクライアント ライブラリを使用しています)。
import json import flask import requests app = flask.Flask(__name__) CLIENT_ID = '123456789.apps.googleusercontent.com' CLIENT_SECRET = 'abc123' # Read from a file or environmental variable in a real app SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly' REDIRECT_URI = 'http://example.com/oauth2callback' @app.route('/') def index(): if 'credentials' not in flask.session: return flask.redirect(flask.url_for('oauth2callback')) credentials = json.loads(flask.session['credentials']) if credentials['expires_in'] <= 0: return flask.redirect(flask.url_for('oauth2callback')) else: headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])} req_uri = 'https://www.googleapis.com/drive/v2/files' r = requests.get(req_uri, headers=headers) return r.text @app.route('/oauth2callback') def oauth2callback(): if 'code' not in flask.request.args: auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code' '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE) return flask.redirect(auth_uri) else: auth_code = flask.request.args.get('code') data = {'code': auth_code, 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, 'redirect_uri': REDIRECT_URI, 'grant_type': 'authorization_code'} r = requests.post('https://oauth2.googleapis.com/token', data=data) flask.session['credentials'] = r.text return flask.redirect(flask.url_for('index')) if __name__ == '__main__': import uuid app.secret_key = str(uuid.uuid4()) app.debug = False app.run()
リダイレクト URI 検証ルール
Google では、デベロッパーがアプリケーションの安全性を維持するために、URI をリダイレクトする際に次の検証ルールを適用します。リダイレクト URI は、以下のルールに準拠している必要があります。以下で説明するドメイン、ホスト、パス、クエリ、スキーム、userinfo の定義については、RFC 3986 セクション 3 をご覧ください。
検証ルール | |
---|---|
スキーム |
リダイレクト URI には、プレーン HTTP ではなく HTTPS スキームを使用する必要があります。ローカルホスト URI(localhost IP アドレス URI を含む)は、このルールから除外されます。 |
ホスト |
ホストに未加工の IP アドレスを指定することはできません。ローカルホストの IP アドレスはこのルールから除外されます。 |
ドメイン |
“googleusercontent.com” にすることはできません。goo.gl など)を含めることはできません。さらに、短縮ドメインを所有するアプリがそのドメインへのリダイレクトを選択した場合、そのリダイレクト URI は、パスに “/google-callback/” を含むか、“/google-callback” で終わる必要があります。 |
ユーザー情報 |
リダイレクト URI に userinfo サブコンポーネントを含めることはできません。 |
[Path] |
リダイレクト URI には、パス トラバーサル(ディレクトリ バックトラッキングとも呼ばれます)を含めることはできません。これは、 |
クエリ |
リダイレクト URI にオープン リダイレクトを含めることはできません。 |
Fragment |
リダイレクト URI にフラグメント コンポーネントを含めることはできません。 |
キャラクター |
リダイレクト URI に次のような文字を含めることはできません。
|
段階的な認可
OAuth 2.0 プロトコルでは、アプリは、スコープによって識別されるリソースにアクセスするための承認をリクエストします。リソースに対して必要なタイミングで承認をリクエストすることは、ユーザー エクスペリエンスのベスト プラクティスとみなされています。それを可能にするため、Google の承認サーバーは段階的な認可をサポートしています。この機能により、必要に応じてスコープをリクエストできます。ユーザーが新しいスコープの権限を付与すると、ユーザーがプロジェクトに付与したすべてのスコープを含むトークンと交換される認証コードが返されます。
たとえば、ユーザーが音楽トラックをサンプリングしてミックスを作成できるアプリでは、ログイン時に必要なリソースがほとんど必要としないため、ログインしたユーザーの名前しか必要としない可能性があります。ただし、完了したミックスを保存するには、Google ドライブへのアクセス権が必要になります。ほとんどのユーザーは、アプリが実際に必要としたときに Google ドライブへのアクセス許可を求められただけで自然になってしまうでしょう。
この場合、ログイン時に、アプリは openid
スコープと profile
スコープをリクエストして基本ログインを実行し、その後、最初のリクエスト時に https://www.googleapis.com/auth/drive.file
スコープをリクエストしてミックスを保存することができます。
増分認可を実装するには、アクセス トークンをリクエストする通常のフローを行いますが、認可リクエストに以前に付与したスコープが含まれていることを確認してください。このアプローチにより、アプリで複数のアクセス トークンを管理する必要がなくなります。
段階的な認可から取得したアクセス トークンには、次のルールが適用されます。
- このトークンを使用して、新しい結合された認可にロール スコープされるスコープに対応するリソースにアクセスできます。
- 統合承認の更新トークンを使用してアクセス トークンを取得する場合、アクセス トークンは統合承認を表し、レスポンスに含まれる任意の
scope
値に使用できます。 - 複数のクライアントから権限付与が要求された場合でも、API プロジェクトにユーザーが付与したすべてのスコープが組み合わされます。たとえば、ユーザーがアプリケーションのデスクトップ クライアントを使用して 1 つのスコープへのアクセス権を付与し、その後、モバイル クライアントを介して同じアプリに別のスコープを付与した場合、統合された認可には両方のスコープが含まれます。
- 統合された承認を表すトークンを取り消すと、関連するユーザーに代わって、その承認のスコープすべてへのアクセス権が同時に取り消されます。
ステップ 1: 認可パラメータを設定するの言語固有のコードサンプルとステップ 2: Google の OAuth 2.0 サーバーへのリダイレクトのサンプルの HTTP/REST リダイレクト URL はすべて、段階的な認可を使用します。以下のコードサンプルは、増分認証を使用するために追加する必要があるコードも示しています。
PHP
$client->setIncludeGrantedScopes(true);
Python
Python で、include_granted_scopes
キーワード引数を true
に設定して、以前に付与されたスコープが認可リクエストに含まれるようにします。次の例で示すように、include_granted_scopes
が設定済みの唯一のキーワード引数ではない場合もあります。
authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
Ruby
auth_client.update!( :additional_parameters => {"include_granted_scopes" => "true"} )
Node.js
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 a best practice. include_granted_scopes: true });
HTTP/REST
GET https://accounts.google.com/o/oauth2/v2/auth? client_id=your_client_id& response_type=code& state=state_parameter_passthrough_value& scope=https%3A//www.googleapis.com/auth/drive.file& redirect_uri=https%3A//oauth2.example.com/code& prompt=consent& include_granted_scopes=true
アクセス トークンの更新(オフライン アクセス)
アクセス トークンは定期的に期限が切れ、関連する API リクエストに対して無効な認証情報になります。トークンに関連付けられたスコープへのオフライン アクセスをリクエストした場合、アクセス トークンの更新をユーザーに求めることなく(ユーザーが不在の場合も含め)、更新できます。
- Google API クライアント ライブラリを使用する場合、クライアント オブジェクトは、そのオブジェクトをオフライン アクセス用に構成している限り、必要に応じてアクセス トークンを更新します。
- クライアント ライブラリを使用していない場合は、ユーザーを Google の OAuth 2.0 サーバーにリダイレクトするときに、
access_type
HTTP クエリ パラメータをoffline
に設定する必要があります。その場合、アクセス トークンと認証コードを交換すると、Google の承認サーバーが更新トークンを返します。その後、アクセス トークンが期限切れになる(または、失効した)場合は、更新トークンを使用して新しいアクセス トークンを取得できます。
オフライン アクセスをリクエストすることは、ユーザーがいないときに Google API にアクセスする必要があるアプリケーションの要件です。たとえば、バックアップ サービスを実行するアプリや、指定された時間にアクションを実行するアプリは、ユーザーが存在しないときにアクセス トークンを更新できる必要があります。デフォルトのアクセススタイルは online
です。
サーバーサイド ウェブ アプリケーション、インストール済みアプリケーション、すべてのデバイスが、承認プロセス中に更新トークンを取得します。更新トークンは通常、クライアントサイド(JavaScript)ウェブ アプリケーションでは使用されません。
PHP
アプリケーションで Google API へのオフライン アクセスが必要な場合は、API クライアントのアクセスタイプを offline
に設定します。
$client->setAccessType("offline");
リクエストされたスコープに対するオフライン アクセスをユーザーが許可した後、そのユーザーがオフラインの間も、API クライアントを使用してユーザーに代わって Google API にアクセスできます。クライアント オブジェクトは、必要に応じてアクセス トークンを更新します。
Python
Python で access_type
キーワード引数を offline
に設定して、ユーザーに権限を再度要求することなくアクセス トークンを更新できるようにします。次の例に示すように、access_type
が設定する唯一のキーワード引数ではない場合もあります。
authorization_url, state = flow.authorization_url( # Enable offline access so that you can refresh an access token without # re-prompting the user for permission. Recommended for web server apps. access_type='offline', # Enable incremental authorization. Recommended as a best practice. include_granted_scopes='true')
リクエストされたスコープに対するオフライン アクセスをユーザーが許可した後、そのユーザーがオフラインの間も、API クライアントを使用してユーザーに代わって Google API にアクセスできます。クライアント オブジェクトは、必要に応じてアクセス トークンを更新します。
Ruby
アプリケーションで Google API へのオフライン アクセスが必要な場合は、API クライアントのアクセスタイプを offline
に設定します。
auth_client.update!( :additional_parameters => {"access_type" => "offline"} )
リクエストされたスコープに対するオフライン アクセスをユーザーが許可した後、そのユーザーがオフラインの間も、API クライアントを使用してユーザーに代わって Google API にアクセスできます。クライアント オブジェクトは、必要に応じてアクセス トークンを更新します。
Node.js
アプリケーションで Google API へのオフライン アクセスが必要な場合は、API クライアントのアクセスタイプを offline
に設定します。
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 a best practice. include_granted_scopes: true });
リクエストされたスコープに対するオフライン アクセスをユーザーが許可した後、そのユーザーがオフラインの間も、API クライアントを使用してユーザーに代わって Google API にアクセスできます。クライアント オブジェクトは、必要に応じてアクセス トークンを更新します。
アクセス トークンには有効期限があります。このライブラリは、更新トークンが自動的に期限切れになるように、新しいアクセス トークンを取得します。トークン イベントを使用すると、常に最新のトークンを確実に格納できます。
oauth2Client.on('tokens', (tokens) => { if (tokens.refresh_token) { // store the refresh_token in your secure persistent database console.log(tokens.refresh_token); } console.log(tokens.access_token); });
このトークン イベントは最初の認証でのみ発生します。更新トークンを受け取る generateAuthUrl
メソッドを呼び出すときに、access_type
を offline
に設定する必要があります。更新トークンを受信するための適切な制約を設定せずにアプリですでに権限を許可している場合は、新しい更新トークンを受け取るようにアプリケーションを再承認する必要があります。
後で refresh_token
を設定する場合は、setCredentials
メソッドを使用します。
oauth2Client.setCredentials({ refresh_token: `STORED_REFRESH_TOKEN` });
クライアントが更新トークンを取得すると、次回の API 呼び出しでアクセス トークンが自動的に取得されて更新されます。
HTTP/REST
アクセス トークンを更新するために、アプリケーションは、次のパラメータを含む HTTPS POST
リクエストを Google の承認サーバー(https://oauth2.googleapis.com/token
)に送信します。
フィールド | |
---|---|
client_id |
API Consoleから取得したクライアント ID。 |
client_secret |
API Consoleから取得したクライアント シークレット。 |
grant_type |
OAuth 2.0 仕様で定義されているように、このフィールドの値は refresh_token に設定する必要があります。 |
refresh_token |
認証コード エクスチェンジから返される更新トークン。 |
次のスニペットは、リクエストの例を示しています。
POST /token HTTP/1.1 Host: oauth2.googleapis.com Content-Type: application/x-www-form-urlencoded client_id=your_client_id& client_secret=your_client_secret& refresh_token=refresh_token& grant_type=refresh_token
ユーザーは、アプリケーションに対して付与されたアクセス権を取り消さない限り、新しいアクセス トークンを含む JSON オブジェクトを返します。次のスニペットは、レスポンスの例を示しています。
{ "access_token": "1/fFAGRNJru1FTz70BzhT3Zg", "expires_in": 3920, "scope": "https://www.googleapis.com/auth/drive.metadata.readonly", "token_type": "Bearer" }
発行される更新トークンの数には上限があります(クライアントとユーザーの組み合わせごとに 1 つずつ、すべてのクライアントで 1 つの上限があります)。更新トークンは長期保存し、有効な限り、継続的に使用する必要があります。アプリケーションがリクエストした更新トークンが多すぎると、これらの制限に達する可能性があります。その場合、古い更新トークンは機能しなくなります。
トークンの取り消し
場合によっては、ユーザーはアプリケーションに付与されたアクセス権を取り消すこともできます。ユーザーは、 アカウント設定にアクセスしてアクセス権を取り消すことができます。詳しくは、アカウントにアクセスできるサードパーティのサイトやアプリのアクセス権を削除するをご覧ください。
アプリケーションに、付与されたアクセス権をプログラマティックに取り消すこともできます。 プログラムによる取り消しは、ユーザーが登録解除したり、アプリを削除したり、アプリで必要な API リソースが大幅に変更された場合に重要です。言い換えると、削除プロセスの一部では、これまでアプリに付与された権限が確実に削除されるよう API リクエストを追加することが可能です。
PHP
プログラムでトークンを取り消すには、revokeToken()
を呼び出します。
$client->revokeToken();
Python
プログラムでトークンを取り消すには、パラメータとしてトークンを含む https://oauth2.googleapis.com/revoke
へのリクエストを行い、Content-Type
ヘッダーを設定します。
requests.post('https://oauth2.googleapis.com/revoke', params={'token': credentials.token}, headers = {'content-type': 'application/x-www-form-urlencoded'})
Ruby
プログラムでトークンを取り消すには、oauth2.revoke
エンドポイントに対して HTTP リクエストを行います。
uri = URI('https://oauth2.googleapis.com/revoke') response = Net::HTTP.post_form(uri, 'token' => auth_client.access_token)
トークンには、アクセス トークンまたは更新トークンを指定できます。トークンがアクセス トークンであり、対応する更新トークンがある場合、更新トークンも取り消されます。
取り消しが正常に処理されると、レスポンスのステータス コードは 200
になります。エラー状態の場合は、エラーコードとともにステータス コード 400
が返されます。
Node.js
プログラムでトークンを取り消すには、/revoke
エンドポイントに HTTPS POST リクエストを送信します。
const https = require('https'); // Build the string for the POST request let postData = "token=" + userCredential.access_token; // Options for POST request to Google's OAuth 2.0 server to revoke a token let postOptions = { host: 'oauth2.googleapis.com', port: '443', path: '/revoke', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(postData) } }; // Set up the request const postReq = https.request(postOptions, function (res) { res.setEncoding('utf8'); res.on('data', d => { console.log('Response: ' + d); }); }); postReq.on('error', error => { console.log(error) }); // Post the request with data postReq.write(postData); postReq.end();
トークン パラメータには、アクセス トークンまたは更新トークンを指定できます。トークンがアクセス トークンであり、対応する更新トークンがある場合、更新トークンも取り消されます。
取り消しが正常に処理されると、レスポンスのステータス コードは 200
になります。エラー状態の場合は、エラーコードとともにステータス コード 400
が返されます。
HTTP/REST
プログラムでトークンを取り消すには、アプリケーションが https://oauth2.googleapis.com/revoke
にリクエストを行い、パラメータとしてトークンを含めます。
curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \ https://oauth2.googleapis.com/revoke?token={token}
トークンには、アクセス トークンまたは更新トークンを指定できます。トークンがアクセス トークンであり、対応する更新トークンがある場合、更新トークンも取り消されます。
取り消しが正常に処理されると、レスポンスの HTTP ステータス コードは 200
になります。エラー状態の場合、エラーコードとともに HTTP ステータス コード 400
が返されます。