このドキュメントでは、ウェブサーバー アプリケーションが Google API クライアント ライブラリまたは Google OAuth 2.0 エンドポイントを使用して、Google API への OAuth 2.0 認証を実装する方法について説明します。
OAuth 2.0 を使用すると、ユーザー名やパスワードなどの情報を非公開にしたまま、特定のデータをアプリケーションと共有できます。たとえば、アプリケーションで OAuth 2.0 を使用して、ユーザーの Google ドライブにファイルを保存する権限を取得できます。
この OAuth 2.0 フローは、ユーザー認証のみを対象としています。機密情報の保存と状態の維持が可能なアプリケーション向けに設計されています。適切に承認されたウェブサーバー アプリケーションは、ユーザーがアプリケーションを操作している間、またはユーザーがアプリケーションを離れた後に、API にアクセスできます。
ウェブサーバー アプリケーションは、特に Cloud API を呼び出してユーザー固有のデータではなくプロジェクトベースのデータにアクセスする場合に、サービス アカウントを使用して API リクエストを認可します。ウェブサーバー アプリケーションは、ユーザー承認と連携してサービス アカウントを使用できます。
クライアント ライブラリ
このページの言語固有のサンプルでは、Google API クライアント ライブラリを使用して OAuth 2.0 認証を実装しています。サンプルコードを実行するには、ご利用の言語のクライアント ライブラリをインストールしてください。
Google API クライアント ライブラリを使用してアプリケーションの OAuth 2.0 フローを処理する場合、クライアント ライブラリは、アプリケーションが単独で処理する必要のある多くのアクションを実行します。たとえば、アプリケーションが保存済みアクセス トークンを使用または更新できるタイミングや、アプリが同意を再取得する必要があるタイミングを決定します。また、クライアント ライブラリが正しいリダイレクト URL を生成し、アクセス トークン用の認証コードを交換するリダイレクト ハンドラの実装にも役立ちます。
サーバー側アプリケーション用の Google API クライアント ライブラリは、次の言語で利用できます。
Prerequisites
プロジェクトでAPI を有効にする
Google API を呼び出すアプリケーションでは、これらの API を API Consoleで有効にする必要があります。
プロジェクトで API を有効にするには:
- Open the API Library は Google API Consoleにあります。
- 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] をクリックします。
- [ウェブ アプリケーション] アプリケーション タイプを選択します。
- フォームに記入し、[Create] をクリックします。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.4 以降(コマンドライン インターフェース(CLI)と JSON 拡張機能がインストールされている)
- Composer 依存関係管理ツール。
-
PHP 用 Google API クライアント ライブラリ:
php composer.phar require google/apiclient:^2.0
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 アクセス トークンの取得
次の手順は、アプリケーションが Google の OAuth 2.0 サーバーとやり取りし、ユーザーに代わって API リクエストを実行することについてユーザーの同意を得る方法を示しています。アプリケーションは、ユーザー承認が必要な 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 ConsoleCredentials pageにあります。 PHP で、 $client = new Google_Client(); $client->setAuthConfig('client_secret.json'); |
||||||
redirect_uri |
必須 ユーザーが承認フローを完了した後、API サーバーがユーザーをリダイレクトする場所を決定します。この値は、クライアントで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI の API Console
Credentials pageと正確に一致している必要があります。この値が、指定された
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 認証サーバーにヒントを提供できます。サーバーはヒントを使用して、ログインフォームにメールアドレスのフィールドを事前に入力するか、適切なマルチログイン セッションを選択することにより、ログインフローを簡素化します。 パラメータ値には、ユーザーの Google ID に相当するメールアドレスまたは 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 ConsoleCredentials 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 サーバーがユーザーをリダイレクトする場所を決定します。この値は、クライアントで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI の API Console
Credentials pageと正確に一致している必要があります。この値が、指定された
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 認証サーバーにヒントを提供できます。サーバーはヒントを使用して、ログインフォームにメールアドレスのフィールドを事前に入力するか、適切なマルチログイン セッションを選択することにより、ログインフローを簡素化します。 パラメータ値には、ユーザーの Google ID に相当するメールアドレスまたは 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 } )
アプリケーションは、このクライアント オブジェクトを使用して、認証リクエスト URL の生成や HTTP リクエストへのアクセス トークンの適用など、OAuth 2.0 オペレーションを実行します。
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 ConsoleCredentials pageにあります。 |
||||||
redirect_uri |
必須 ユーザーが承認フローを完了した後、API サーバーがユーザーをリダイレクトする場所を決定します。この値は、クライアントで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI の API Console
Credentials pageと正確に一致している必要があります。この値が、指定された
|
||||||
response_type |
必須 Google OAuth 2.0 エンドポイントが認証コードを返すかどうかを指定します。 ウェブサーバー アプリケーションのパラメータ値を |
||||||
scope |
必須 アプリケーションがユーザーの代わりにアクセスできるリソースを識別するスコープのスペース区切りのリスト。これらの値は、Google がユーザーに表示する同意画面に通知します。 スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストでき、ユーザーはアプリケーションに付与するアクセス権の量を制御できます。したがって、リクエストされたスコープの数とユーザーの同意を得る可能性の間には、逆関係があります。 可能な限り、アプリケーションにおいてコンテキスト内で承認スコープへのアクセスをリクエストすることをおすすめします。増分承認により、コンテキスト内でユーザーデータへのアクセスをリクエストすることで、アプリケーションがアクセスを必要とする理由をユーザーが簡単に理解できるようになります。 |
||||||
access_type |
推奨
ユーザーがブラウザにいないときに、アプリケーションがアクセス トークンを更新できるかどうかを示します。有効なパラメータ値は、デフォルト値の ユーザーがブラウザにいないときにアプリケーションでアクセス トークンを更新する必要がある場合は、値を |
||||||
state |
推奨
認証リクエストと認証サーバーのレスポンスとの間の状態を維持するために、アプリケーションが使用する任意の文字列値を指定します。
ユーザーがアプリケーションのアクセス リクエストを同意または拒否した後、 このパラメータは、ユーザーをアプリ内の適切なリソースに誘導する、ノンスを送信する、クロスサイト リクエスト フォージェリを軽減するなど、いくつかの目的で使用できます。 |
||||||
include_granted_scopes |
省略可
アプリケーションが増分認可を使用して、状況に応じて追加のスコープへのアクセスをリクエストできるようにします。このパラメータの値を |
||||||
login_hint |
省略可
認証しようとしているユーザーがアプリケーションで実行されている場合は、このパラメータを使用して Google 認証サーバーにヒントを提供できます。サーバーはヒントを使用して、ログインフォームにメールアドレスのフィールドを事前に入力するか、適切なマルチログイン セッションを選択することにより、ログインフローを簡素化します。 パラメータ値には、ユーザーの Google ID に相当するメールアドレスまたは |
||||||
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 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 の Android 用 AppAuth などの Android ライブラリを使用する必要があります。
このエラーは、Android アプリが埋め込みユーザー エージェントで一般的なウェブリンクを開き、ユーザーがサイトから Google の OAuth 2.0 認証エンドポイントに移動すると、このエラーが発生することがあります。デベロッパーは、Android アプリリンク ハンドラまたはデフォルトのブラウザアプリの両方を含むオペレーティング システムのデフォルトのリンクハンドラで一般的なリンクを開くことができるようにする必要があります。Android カスタムタブ ライブラリもサポートされているオプションです。
iOS
iOS と macOS のデベロッパーが WKWebView
で認証リクエストを開くと、このエラーが発生することがあります。代わりに、iOS 用 Google ログインや OpenID Foundation の iOS 用 AppAuth などの iOS ライブラリを使用する必要があります。
このエラーは、iOS または macOS アプリが埋め込みユーザー エージェントで一般的なウェブリンクを開き、ユーザーがサイトから Google の OAuth 2.0 認証エンドポイントにアクセスしたときに発生する場合があります。デベロッパーは、ユニバーサル リンク ハンドラまたはデフォルトのブラウザアプリの両方を含む、オペレーティング システムのデフォルトのリンクハンドラで一般的なリンクを開くことができるようにする必要があります。SFSafariViewController
ライブラリもサポートされているオプションです。
org_internal
リクエストに含まれる OAuth クライアント ID は、特定の Google Cloud 組織内の Google アカウントへのアクセスを制限するプロジェクトの一部となっています。この構成オプションについて詳しくは、OAuth 同意画面の設定に関するヘルプ記事のユーザータイプのセクションをご覧ください。
redirect_uri_mismatch
認可リクエストで渡された redirect_uri
が、OAuth クライアント ID の承認されたリダイレクト URI と一致しません。 Google API Console Credentials pageで承認済みのリダイレクト URI を確認してください。
ステップ 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 |
Credentials pageから取得したクライアント シークレット。 API Console |
code |
最初のリクエストから返された認証コード。 |
grant_type |
OAuth 2.0 仕様で定義されている場合、このフィールドの値は authorization_code に設定する必要があります。 |
redirect_uri |
指定された client_id の API ConsoleCredentials 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" }
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 ドライブ内のメタデータにアクセスすることを JSON ファイル形式で Google ドライブに出力します。
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.0
- 次の内容の
index.php
とoauth2callback.php
を作成します。 - PHP を提供するように構成されたウェブサーバーで、例を実行します。PHP 5.4 以降を使用している場合は、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 は、上記の規則に従う必要があります。以下で説明するドメイン、ホスト、パス、クエリ、スキーム、ユーザー情報の定義については、RFC 3986 セクション 3 をご覧ください。
検証ルール | |
---|---|
スキーム |
リダイレクト URI は、プレーン HTTP ではなく HTTPS スキームを使用する必要があります。ローカルホスト URI(localhost IP アドレス URI を含む)は、このルールから除外されます。 |
ホスト |
ホストには、未加工の IP アドレスは使用できません。ローカルホスト IP アドレスはこのルールから除外されます。 |
ドメイン |
“googleusercontent.com” にすることはできません。goo.gl )を含めることはできません。さらに、短縮ドメインを所有するアプリがそのドメインにリダイレクトすることを選択した場合、そのリダイレクト URI はパスに “/google-callback/” を含むか、“/google-callback” で終わる必要があります。 |
Userinfo |
リダイレクト URI に userinfo サブコンポーネントを含めることはできません。 |
[Path] |
リダイレクト URI には、 |
検索キーワード |
リダイレクト URI にオープン リダイレクトを含めることはできません。 |
フラグメント |
リダイレクト URI にフラグメント コンポーネントを含めることはできません。 |
文字 |
リダイレクト URI には、次のような文字は使用できません。
|
増分承認
OAuth 2.0 プロトコルでは、アプリはスコープによって識別されるリソースにアクセスするための承認をリクエストします。リソースの承認を必要なときにリクエストすることをおすすめします。これを可能にするため、Google の承認サーバーは増分承認に対応しています。この機能を使用すると、必要に応じてスコープをリクエストできます。ユーザーが新しいスコープの権限を付与すると、ユーザーがプロジェクトに付与したすべてのスコープを含むトークンと交換できる認証コードを返します。
たとえば、ユーザーが音楽トラックをサンプリングしてミックスを作成できるアプリでは、ログイン時に必要となるリソースがほとんどなく、ログインする人の名前だけで十分です。ただし、完成したミックスを保存するには、Google ドライブにアクセスする必要があります。ほとんどのユーザーは、実際にアプリが必要とした時点で Google ドライブへのアクセスを要求するだけで、自然にできませんでした。
この場合、アプリはログイン時に openid
スコープと profile
スコープをリクエストして基本的なログインを行い、その後、最初のリクエスト時にミックスリストを保存する https://www.googleapis.com/auth/drive.file
スコープをリクエストします。
段階的認証を実装するには、アクセス トークンをリクエストする通常のフローを完了しますが、認可リクエストに以前に付与したスコープが含まれていることを確認します。このアプローチにより、アプリは複数のアクセス トークンを管理する必要がありません。
増分承認から取得したアクセス トークンには、以下のルールが適用されます。
- このトークンを使用して、新しい結合された承認にロールされたスコープに対応するリソースにアクセスできます。
- アクセス トークンを取得するために結合された認証の更新トークンを使用する場合、アクセス トークンは結合された認証を表し、レスポンスに含まれる任意の
scope
値に使用できます。 - 権限の組み合わせには、権限付与が別のクライアントからリクエストされた場合でも、ユーザーが API プロジェクトに付与したすべてのスコープが含まれます。たとえば、ユーザーがアプリケーションのデスクトップ クライアントを使用して一方のスコープへのアクセスを許可した後、モバイル クライアントを介して同じアプリケーションに別のスコープを付与した場合、統合された承認には両方のスコープが含まれます。
- 複数の承認を組み合わせたトークンを取り消すと、関連するユーザーの代理での、その承認のすべてのスコープへのアクセスも同時に取り消されます。
ステップ 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
がエラーコードとともに返されます。