ウェブサーバー アプリケーションに OAuth 2.0 を使用する

このドキュメントでは、ウェブサーバー アプリケーションが Google API クライアント ライブラリまたは Google アクセスするための OAuth 2.0 認可を実装する OAuth 2.0 エンドポイント Google API

OAuth 2.0 を使用すると、ユーザーは特定のデータをアプリケーションと共有する一方で、 他の情報を保護します。 たとえば、アプリケーションは OAuth 2.0 を使用して、 ユーザーが自分の Google ドライブにファイルを保存できるようにしています。

この OAuth 2.0 フローはユーザー認証専用です。アプリケーション向けに設計されており、 保存し、状態を維持できます。適切に認可されたウェブサーバー ユーザーがアプリケーションを操作している間、またはユーザーが操作した後に、API にアクセスできる アプリから離れます

ウェブサーバー アプリケーションでは、もよく使用されます。 (特に Cloud APIs を呼び出してアクセスする場合) ユーザー固有のデータではなくプロジェクト ベース データを使用します。ウェブサーバー アプリケーションは、サービスを使用して 認証と認可が必要です。

クライアント ライブラリ

このページの言語固有の例では、 実装する Google API クライアント ライブラリ OAuth 2.0 認証。コードサンプルを実行するには、まず クライアント ライブラリを使用できます。

Google API クライアント ライブラリを使用してアプリケーションの OAuth 2.0 フローを処理する場合、クライアントは ライブラリは、本来はアプリケーションが独自に処理しなければならない多くのアクションを実行します。対象 たとえば、保存されたアクセス トークンをアプリケーションが使用または更新できるタイミングや、 アプリケーションが同意を再取得する必要がある場合。また、クライアント ライブラリは正しいリダイレクトを URL です。認証コードをアクセス トークンと交換するリダイレクト ハンドラの実装に役立ちます。

サーバーサイド アプリケーション用の Google API クライアント ライブラリは、以下の言語で利用できます。

前提条件

プロジェクトでAPI を有効にする

Google API を呼び出すアプリケーションでは、 API Console。

プロジェクトで API を有効にするには:

  1. Open the API Library Google API Console。
  2. If prompted, select a project, or create a new one.
  3. API Library には、利用可能なすべての API がプロダクト別にグループ化されて表示されます。 ファミリーと人気度です。有効にしたい API がリストに表示されない場合は、検索を使用して 該当するプロダクト ファミリーの [すべて表示] をクリックしてください。
  4. 有効にする API を選択し、[有効にする] ボタンをクリックします。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

承認認証情報を作成する

OAuth 2.0 を使用して Google API にアクセスするアプリケーションには、認証情報が必要です。 アプリケーションを識別する API を Google の OAuth 2.0 サーバーに提供します。次の手順では、 プロジェクトの認証情報を作成します。これにより、アプリケーションは認証情報を使用して API にアクセスできるようになります。 有効にする必要があります

  1. Go to the Credentials page.
  2. [認証情報を作成] > [OAuth クライアント ID] をクリックします。
  3. アプリケーションの種類として [ウェブ アプリケーション] を選択します。
  4. フォームに入力し、[作成] をクリックします。言語とフレームワークを使用するアプリケーション (例: PHP、Java、Python、Ruby、.NET など)では、承認済みのリダイレクト URI を指定する必要があります。「 リダイレクト URI は、OAuth 2.0 サーバーがレスポンスを送信できるエンドポイントです。これらの エンドポイントが Google の検証ルールを遵守している必要があります。

    テスト用に、ローカルマシンを参照する URI を指定できます。たとえば、 http://localhost:8080。このことを念頭に置いて、 このドキュメントの例では、リダイレクト URI として http://localhost:8080 を使用しています。

    アプリの認証エンドポイントを設計することをおすすめします。これにより、 アプリケーションの他のリソースに認証コードが公開されないように できます。

認証情報を作成したら、client_secret.json ファイルを API Console。安全にアクセスできる場所にファイルを 指定する必要があります。

アクセス スコープを特定する

スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストできるだけでなく、 ユーザーがアプリケーションに付与するアクセス権の量を制御できます。したがって、 リクエストするスコープの数と、問題が発生する可能性と ユーザーの同意を得る

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-authgoogle-auth-oauthlibgoogle-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.6 以降
  • Ruby 用 Google 認証ライブラリ:

    gem install googleauth
  • Sinatra Ruby ウェブ アプリケーション フレームワーク。

    gem install sinatra

Node.js

このドキュメントの Node.js コードサンプルを実行するには、次のものが必要です。

  • メンテナンスの LTS、アクティブな LTS、または Node.js の現在のリリース。
  • Google API Node.js クライアント:

    npm install googleapis crypto express express-session

HTTP/REST

ライブラリをインストールしなくても、OAuth 2.0 を直接呼び出すことができます 提供します

OAuth 2.0 アクセス トークンの取得

次の手順は、アプリケーションが Google の OAuth 2.0 サーバーとやり取りして認証情報を取得する方法を示しています。 ユーザーの代わりに API リクエストを実行することへのユーザーの同意。アプリケーションは、 ユーザーの承認を必要とする Google API リクエストを実行する前に、ユーザーの同意を得る必要があります。

以下に、この手順の概要を示します。

  1. アプリケーションで必要な権限を特定します。
  2. アプリケーションは、要求されたリストとともにユーザーを Google にリダイレクトします。 付与できます。
  3. この権限をアプリケーションに付与するかどうかは、ユーザーが決定します。
  4. アプリケーションで、ユーザーが決定した内容を確認します。
  5. ユーザーがリクエストした権限を付与すると、アプリケーションは次のために必要なトークンを取得します。 ユーザーの代わりに API リクエストを発行します

ステップ 1: 認可パラメータを設定する

最初のステップは、承認リクエストを作成することです。このリクエストでは、 アプリケーションを識別し、ユーザーに付与する必要のある権限を定義します。 説明します。

  • OAuth 2.0 の認証と認可に Google クライアント ライブラリを使用する場合は、 パラメータを定義するオブジェクトを作成して構成できます。
  • Google OAuth 2.0 エンドポイントを直接呼び出す場合は、URL を生成し、 パラメータを指定します。

以下のタブでは、ウェブサーバー アプリケーションでサポートされる認可パラメータを定義します。「 言語固有の例では、クライアント ライブラリまたは認可ライブラリを使用して、 これらのパラメータを設定するオブジェクトを構成します。

PHP

以下のコード スニペットでは、Google\Client() オブジェクトを作成します。このオブジェクトは、 パラメータを指定します。

このオブジェクトは、client_secret.json ファイルの情報を使用してクライアントを識別します。 説明します。(詳細については、認証情報の作成をご覧ください)。 表示されます)。このオブジェクトは、アプリが権限をリクエストしているスコープも特定します。 アプリケーションの認証エンドポイントへの URL を指定します。このエンドポイントは、 Google の OAuth 2.0 サーバーです。最後に、オプションの access_typeinclude_granted_scopes パラメータ。

たとえば、このコードはユーザーの IP アドレスへの読み取り専用のオフライン アクセスを Google ドライブ:

$client = new Google\Client();

// Required, call the setAuthConfig function to load authorization credentials from
// client_secret.json file.
$client->setAuthConfig('client_secret.json');

// Required, to set the scope value, call the addScope function
$client->addScope(Google\Service\Drive::DRIVE_METADATA_READONLY);

// Required, call the setRedirectUri function to specify a valid redirect URI for the
// provided client_id
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');

// Recommended, 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');

// Recommended, call the setState function. Using a state value can increase your assurance that
// an incoming connection is the result of an authentication request.
$client->setState($sample_passthrough_value);

// Optional, if your application knows which user is trying to authenticate, it can use this
// parameter to provide a hint to the Google Authentication Server.
$client->setLoginHint('hint@example.com');

// Optional, call the setPrompt function to set "consent" will prompt the user for consent
$client->setPrompt('consent');

// Optional, call the setIncludeGrantedScopes function with true to enable incremental
// authorization
$client->setIncludeGrantedScopes(true);

Python

次のコード スニペットでは、google-auth-oauthlib.flow モジュールを使用して、 表示されます。

このコードは、Flow オブジェクトを作成し、 ダウンロードした client_secret.json ファイル内の情報について、 認証情報の作成。また、このオブジェクトは スコープと、アプリケーションの URL が関連付けられています。 認証エンドポイントを指定します。最後に、 オプションの access_type パラメータと include_granted_scopes パラメータを設定します。

たとえば、このコードはユーザーの IP アドレスへの読み取り専用のオフライン アクセスを Google ドライブ:

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Required, call the from_client_secrets_file method to retrieve the client ID from a
# client_secret.json file. The client ID (from that file) and access scopes are required. (You can
# also use the from_client_config method, which passes the client configuration as it originally
# appeared in a client secrets file but doesn't access the file itself.)
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=['https://www.googleapis.com/auth/drive.metadata.readonly'])

# Required, 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(
    # Recommended, 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',
    # Optional, enable incremental authorization. Recommended as a best practice.
    include_granted_scopes='true',
    # Optional, if your application knows which user is trying to authenticate, it can use this
    # parameter to provide a hint to the Google Authentication Server.
    login_hint='hint@example.com',
    # Optional, set prompt to 'consent' will prompt the user for consent
    prompt='consent')

Ruby

作成した client_secrets.json ファイルを使用して、 説明します。クライアント オブジェクトを構成するときに、アプリケーションに必要なスコープを指定します。 レスポンスを処理するアプリケーションの認証エンドポイントへの URL とともに、 OAuth 2.0 サーバーから返されます。

たとえば、このコードはユーザーの IP アドレスへの読み取り専用のオフライン アクセスを Google ドライブ:

require 'google/apis/drive_v3'
require "googleauth"
require 'googleauth/stores/redis_token_store'

client_id = Google::Auth::ClientId.from_file('/path/to/client_secret.json')
scope = 'https://www.googleapis.com/auth/drive.metadata.readonly'
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
authorizer = Google::Auth::WebUserAuthorizer.new(client_id, scope, token_store, '/oauth2callback')

アプリケーションはこのクライアント オブジェクトを使用して、OAuth 2.0 のオペレーションを実行します。たとえば、 認証リクエスト URL へのアクセスと、HTTP リクエストへのアクセス トークンの適用について説明します。

Node.js

次のコード スニペットは、google.auth.OAuth2 オブジェクトを作成します。このオブジェクトは、 パラメータを指定します。

このオブジェクトは、client_secret.json ファイルからの情報を使用してアプリケーションを識別します。宛先 アクセス トークンを取得するためにユーザーに権限をリクエストする場合は、同意ページにリダイレクトします。 同意ページの URL を作成するには:

const {google} = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * 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 secure random state value.
const state = crypto.randomBytes(32).toString('hex');

// Store state in the session
req.session.state = state;

// 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,
  // Include the state parameter to reduce the risk of CSRF attacks.
  state: state
});

重要な注意事項 - 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 サーバーがユーザーをリダイレクトする場所を指定します。 承認フローを実行しますこの値は、サービスに対して承認されたリダイレクト URI のいずれかと完全に一致する必要があります。 OAuth 2.0 クライアント(クライアントの API Console Credentials page。この値が一致する 指定された client_id の承認済みのリダイレクト URI を取得すると、 redirect_uri_mismatch エラー。

http または https スキーム、大文字 / 小文字、末尾のスラッシュは (「/」)がすべて一致する必要があります。

response_type 必須

Google OAuth 2.0 エンドポイントが認証コードを返すかどうかを決定します。

ウェブサーバー アプリケーションのパラメータ値を code に設定します。

scope 必須

スペース区切り アプリケーションがアクセスできるリソースを識別するスコープのリスト 委任できます。これらの値は、Google がユーザーに表示する同意画面を できます。

スコープを使用すると、アプリケーションは必要なリソースへのアクセスのみをリクエストできるようになります。 付与するアクセス権のレベルも制御できます 説明します。したがって、リクエストされるスコープの数には逆相関があります。 ユーザーの同意を得る可能性などです。

状況に応じて、認可スコープへのアクセスをアプリケーションでリクエストすることをおすすめします。 可能な限り避けてください。コンテキスト内で、以下を使用してユーザーデータへのアクセスをリクエストする 段階的な承認により、ユーザーがより簡単に アプリケーションがリクエストしているアクセスを必要とする理由を理解する。

access_type 推奨

ユーザーが存在しない場合にアプリケーションがアクセス トークンを更新できるかどうかを示します アクセスできます。有効なパラメータ値は online です。これがデフォルトの value、offlineなどです。

アプリケーションでアクセス トークンを更新する必要がある場合は、値を offline に設定します。 ユーザーがブラウザにアクセスしていないとき。これはアクセスを更新する方法です。 トークンを使用します。この値は、 サーバーが更新トークンアクセス トークンを返すようリクエストします。 認証コードをトークンと交換します。

state 推奨

アプリケーション間で状態を維持するために、アプリケーションが使用する文字列値 認可リクエストと認可サーバーのレスポンスで構成されます。 サーバーは、送信したコードを name=value ペアとして の URL クエリ コンポーネント(?redirect_uri ユーザーがアプリケーションの アクセス リクエストだけです。

このパラメータは、ユーザーを アプリケーション内の適切なリソースの確認、ノンスの送信、クロスサイト リクエストの軽減 できます。redirect_uri は推測できるため、state を使用します。 値を使用すると、受信接続が特定のサーバーに対する 構成されます。ユーザーがランダムな文字列を生成したり、Cookie や Cookie のハッシュをエンコードしたりした場合、 クライアントの状態を取得する別の値が必要な場合は、 さらに、リクエストとレスポンスが同じブラウザから発信されたこと、 次のような攻撃から保護します。 クロスサイト リクエスト 偽造。詳しくは、 OpenID Connect state トークンを作成して確認する方法の例をご覧ください。

include_granted_scopes 省略可

アプリケーションが増分認可を使用して、追加リソースへのアクセスをリクエストできるようにする スコープです。このパラメータの値を true に設定し、 アクセス トークンを取得した場合、その新しいアクセス トークンは、 ユーザーが以前にアプリケーションへのアクセスを許可した場所。詳しくは、 段階的承認のセクションをご覧ください。

login_hint 省略可

認証しようとしているユーザーをアプリケーションで認識している場合は、このパラメータを使用できます。 Google 認証サーバーにヒントを提供します。サーバーはヒントを使用して、 ログイン フォームのメール フィールドにあらかじめ入力するか、 適切なマルチログインセッションを選択します

パラメータ値には、メールアドレスまたは sub 識別子を設定します。 ユーザーの Google ID に相当します。

prompt 省略可

ユーザーに表示するプロンプトのリスト。スペースで区切られ、大文字と小文字が区別されます。この操作を このパラメータを指定すると、プロジェクトが初めて作成されたときにのみ アクセスをリクエストします。<ph type="x-smartling-placeholder"></ph>をご覧ください。 再同意を求めるで詳細をご確認ください。

指定できる値は次のとおりです。

none 認証画面や同意画面は表示しないでください。次のように指定することはできません。 使用できます。
consent ユーザーに同意を求めます。
select_account アカウントの選択をユーザーに促します。

ステップ 2: Google の OAuth 2.0 サーバーにリダイレクトする

ユーザーを Google の OAuth 2.0 サーバーにリダイレクトして、認証と認可を開始する 認証プロセスに進みます。通常これは、アプリケーションが最初にそのデータにアクセスする必要があるときに行われます。 保護します。段階的な承認の場合、 この手順は、実行する追加のリソースにアプリケーションが最初にアクセスする必要がある場合にも発生します。 まだアクセス権がありません。

PHP

  1. Google の OAuth 2.0 サーバーからアクセスをリクエストするための URL を生成します。
    $auth_url = $client->createAuthUrl();
  2. ユーザーを $auth_url にリダイレクトします。
    header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));

Python

この例では、Flask ウェブを使用して認証 URL にユーザーをリダイレクトする方法を示します。 アプリケーション フレームワーク:

return flask.redirect(authorization_url)

Ruby

  1. Google の OAuth 2.0 サーバーからアクセスをリクエストするための URL を生成します。
    auth_uri = authorizer.get_authorization_url(login_hint: user_id, request: request)
  2. ユーザーを auth_uri にリダイレクトします。

Node.js

  1. ステップ 1 で生成された URL authorizationUrl を使用します。 generateAuthUrl メソッドを使用して Google の OAuth 2.0 サーバーからアクセスをリクエストします。
  2. ユーザーを authorizationUrl にリダイレクトします。
    res.redirect(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 アカウントはリクエストされた 1 つ以上のスコープを承認できません Google Workspace 管理者が 手動で行う必要はありませんGoogle Workspace 管理者用ヘルプ記事をご覧ください どの第三者と内部アプリが Google Workspace データにアクセスする 管理者がすべてのスコープまたは機密 / 機密情報へのアクセスを制限する方法について詳しくは、 OAuth クライアント ID にアクセスが明示的に付与されるまで、制限付きのスコープを設定できます。

disallowed_useragent

認可エンドポイントが、Google の許可されていない埋め込みユーザー エージェント内に表示される OAuth 2.0 ポリシー

Android

Android デベロッパーが認証リクエストを開くと、このエラー メッセージが表示されることがあります。 android.webkit.WebView。 代わりに、次のような Android ライブラリを使用する必要があります。 Android 向け Google ログインまたは OpenID Foundation Android 用の AppAuth

このエラーは、Android アプリが ユーザーが Google の OAuth 2.0 認可エンドポイントに移動すると、 できます。デベロッパーは、一般的なリンクを オペレーティング システムには、 Android アプリリンク デフォルトのブラウザアプリを使用できます。「 Android カスタムタブ ライブラリもサポートされています。

iOS

iOS および macOS のデベロッパーにおいて、承認リクエストを Google 管理コンソールで開くと、このエラーが発生する場合があります WKWebView。 代わりに、次のような iOS ライブラリを使用する必要があります。 iOS 向け Google ログインまたは OpenID Foundation iOS 用の AppAuth

このエラーは、iOS アプリまたは macOS アプリで一般的なウェブリンクが ユーザーが埋め込みユーザー エージェントを作成し、ユーザーが Google の OAuth 2.0 認可エンドポイントに できます。デベロッパーは、一般的なリンクを オペレーティング システムには、 ユニバーサル リンク デフォルトのブラウザアプリを使用できます。「 SFSafariViewController ライブラリもサポートされています。

org_internal

リクエストの OAuth クライアント ID は、プロジェクト内の Google アカウントへのアクセスを制限する Google Cloud 組織。 この設定オプションの詳細については、 ユーザーの種類 (OAuth 同意画面の設定に関するヘルプ記事)をご覧ください。

invalid_client

OAuth クライアント シークレットが正しくありません。詳しくは、 OAuth クライアント 構成(このリクエストに使用するクライアント ID とシークレットなど)が含まれます。

invalid_grant

アクセス トークンを更新するとき、または 段階的な承認では、トークンの有効期限が切れているか、 無効になりました。 ユーザーを再度認証し、新しいトークンを取得するためのユーザーの同意を求めます。続行する場合 このエラーを表示するには、アプリケーションが正しく構成されていて、 正しいトークンとパラメータを使用して検証する必要があります。それ以外の場合、ユーザー アカウントに 削除されたか無効になっています

redirect_uri_mismatch

承認リクエストで渡された redirect_uri が、承認済みのものと一致しません OAuth クライアント ID のリダイレクト URI。URL にある承認済みのリダイレクト URI を Google API Console Credentials page

redirect_uri パラメータは、以下を含む OAuth 帯域外(OOB)フローを指すことがあります。 非推奨となり、サポートされなくなりました。詳しくは、 移行ガイドを参照し、 統合されています

invalid_request

リクエストになんらかの問題がありました。これには、いくつかの理由が考えられます。

  • リクエストの形式が正しくありません
  • リクエストに必須パラメータが含まれていませんでした
  • リクエストで、Google でサポートされていない認証方法が使用されています。OAuth を確認する 推奨される統合方法が使用されています

ステップ 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

コールバック ページで、googleauth ライブラリを使用して認可サーバーを検証する レスポンスが返されます。authorizer.handle_auth_callback_deferred メソッドを使用して、 認証コードを作成し、最初に認証をリクエストした URL にリダイレクトします。この ユーザーのセッションに結果を一時的に保管することで、コードの交換を先延ばしにします。

  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url

Node.js

認証コードをアクセス トークンと交換するには、getToken を使用します。 メソッド:

const url = require('url');

// Receive the callback from Google's OAuth 2.0 server.
app.get('/oauth2callback', async (req, res) => {
  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 if (q.state !== req.session.state) { //check state value
    console.log('State mismatch. Possible CSRF attack');
    res.end('State mismatch. Possible CSRF attack');
  } else { // 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 API Consoleから取得したクライアント ID Credentials page
client_secret API Consoleから取得したクライアント シークレット。 Credentials page
code 最初のリクエストから返された認証コード。
grant_type OAuth 2.0 の の場合、このフィールドの値を authorization_code に設定する必要があります。
redirect_uri プロジェクトのリダイレクト URI の 1 つを API Console 指定された の Credentials page client_id

次のスニペットはサンプル リクエストを示しています。

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 オブジェクトを返します。 更新トークンの 2 つです 更新トークンは、アプリケーションで access_type が設定されている場合にのみ返されます。 パラメータを offline に指定( 認可サーバーを構成します

レスポンスには、次のフィールドが含まれます。

フィールド
access_token Google API リクエストを承認するためにアプリケーションが送信するトークン。
expires_in アクセス トークンの残りの存続期間(秒)。
refresh_token 新しいアクセス トークンの取得に使用できるトークン。更新トークンは、更新トークンが ユーザーがアクセス権を取り消します。 繰り返しになりますが、このフィールドは access_type を設定した場合のみ、このレスポンスに存在します。 パラメータを Google の承認サーバーへの最初のリクエストの 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 を呼び出します。

  1. 新しい Google\Client オブジェクトにアクセス トークンを適用する必要がある場合、 たとえば、アクセス トークンをユーザー セッションに保存した場合は、 setAccessToken メソッド:
    $client->setAccessToken($access_token);
  2. 呼び出す API のサービス オブジェクトを作成します。サービス オブジェクトを作成するには、 承認済みの Google\Client オブジェクトを API のコンストラクタに提供します。 選択します。 たとえば、Drive API を呼び出すには次のようにします。
    $drive = new Google\Service\Drive($client);
  3. API サービスにリクエストを送信するには、 インターフェースを提供します。 たとえば、認証済みユーザーの Google ドライブ内のファイルを一覧表示するには、次のようにします。
    $files = $drive->files->listFiles(array())->getItems();

Python

アクセス トークンを取得したら、アプリケーションはそのトークンを使用して、 ロールを委任できます。ユーザー固有の認証情報を使用する 呼び出す API のサービス オブジェクトを作成し、そのオブジェクトを使用して リクエストの数を減らします。

  1. 呼び出す API のサービス オブジェクトを作成します。サービス オブジェクトを作成するには、 googleapiclient.discovery ライブラリの build メソッドを、 API の名前とバージョン、ユーザー認証情報。 たとえば、Drive API のバージョン 3 を呼び出すには、次のようにします。
    from googleapiclient.discovery import build
    
    drive = build('drive', 'v2', credentials=credentials)
  2. API サービスにリクエストを送信するには、 インターフェースを提供します。 たとえば、認証済みユーザーの Google ドライブ内のファイルを一覧表示するには、次のようにします。
    files = drive.files().list().execute()

Ruby

アクセス トークンを取得したら、アプリケーションはそのトークンを使用して、API リクエストを ロールを委任できます。ユーザー固有の認証情報を使用する 呼び出す API のサービス オブジェクトを作成し、そのオブジェクトを使用して リクエストの数を減らします。

  1. 呼び出す API のサービス オブジェクトを作成します。 たとえば、Drive API のバージョン 3 を呼び出すには、次のようにします。
    drive = Google::Apis::DriveV3::DriveService.new
  2. サービスの認証情報を設定します。
    drive.authorization = credentials
  3. API サービスにリクエストを送信するには、 インターフェース サービス オブジェクトによって指定されます。 たとえば、認証済みユーザーの Google ドライブ内のファイルを一覧表示するには、次のようにします。
    files = drive.list_files

または、API に メソッドに options パラメータを追加します。

files = drive.list_files(options: { authorization: credentials })

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

アプリケーションがアクセス トークンを取得したら、そのトークンを使用して Google Cloud API を呼び出すことができます。 API の代理操作です。 ユーザー アカウント(API に必要なアクセス スコープが付与されている場合)そのためには API へのリクエストのアクセス トークン(access_token クエリまたは パラメータまたは Authorization HTTP ヘッダー Bearer 値を指定します。可能であれば クエリ文字列はサーバーログに表示される傾向があるため、HTTP ヘッダーの使用をおすすめします。ほとんどの クライアント ライブラリを使用して Google API の呼び出しを設定できます(例: Drive Files API の呼び出しを参照)。

すべての Google API を試して、 OAuth 2.0 Playground

HTTP GET の例

呼び出しは、 drive.files エンドポイント(Drive Files API)Authorization: Bearer HTTP を使用 次のようになります。独自のアクセス トークンを指定する必要があります。

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 形式のリストを ユーザーが認証を行い、アプリケーションがユーザーのドライブのメタデータにアクセスすることに同意します。

PHP

この例を実行するには:

  1. API Consoleで、ローカルマシンの URL を リダイレクト URL のリスト。たとえば、http://localhost:8080 を追加します。
  2. 新しいディレクトリを作成し、そのディレクトリに移動します。次に例を示します。
    mkdir ~/php-oauth2-example
    cd ~/php-oauth2-example
  3. Google API クライアントを ライブラリComposer を使用):
    composer require google/apiclient:^2.10
  4. コンテンツを含むファイル index.phpoauth2callback.php を作成する ご覧ください
  5. 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'])) {
  // Generate and set state value
  $state = bin2hex(random_bytes(16));
  $client->setState($state);
  $_SESSION['state'] = $state;

  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  // Check the state value
  if (!isset($_GET['state']) || $_GET['state'] !== $_SESSION['state']) {
    die('State mismatch. Possible CSRF attack.');
  }
  $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 フレームワークを使用します。これは、 OAuth 2.0 をテストできるウェブ アプリケーションを http://localhost:8080 で実行します。 できます。この 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_v3'
require 'sinatra'
require 'googleauth'
require 'googleauth/stores/redis_token_store'

configure do
  enable :sessions

  set :client_id, Google::Auth::ClientId.from_file('/path/to/client_secret.json')
  set :scope, Google::Apis::DriveV3::AUTH_DRIVE_METADATA_READONLY
  set :token_store, Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
  set :authorizer, Google::Auth::WebUserAuthorizer.new(settings.client_id, settings.scope, settings.token_store, '/oauth2callback')
end

get '/' do
  user_id = settings.client_id.id
  credentials = settings.authorizer.get_credentials(user_id, request)
  if credentials.nil?
    redirect settings.authorizer.get_authorization_url(login_hint: user_id, request: request)
  end
  drive = Google::Apis::DriveV3::DriveService.new
  files = drive.list_files(options: { authorization: credentials })
  "<pre>#{JSON.pretty_generate(files.to_h)}</pre>"
end

get '/oauth2callback' do
  target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(request)
  redirect target_url
end

Node.js

この例を実行するには:

  1. API Consoleに、デバイスの URL を リダイレクト URL のリストに追加します。たとえば、 http://localhost
  2. メンテナンス LTS、アクティブな LTS、または現在のリリースの Node.js がインストールされていること。
  3. 新しいディレクトリを作成し、そのディレクトリに移動します。次に例を示します。
    mkdir ~/nodejs-oauth2-example
    cd ~/nodejs-oauth2-example
  4. Install the Google API Client Library for Node.js using npm:
    npm install googleapis
  5. 以下の内容でファイル main.js を作成します。
  6. サンプルを実行します。
    node .\main.js

main.js

const http = require('http');
const https = require('https');
const url = require('url');
const { google } = require('googleapis');
const crypto = require('crypto');
const express = require('express');
const session = require('express-session');

/**
 * 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'
];
/* 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 app = express();

  app.use(session({
    secret: 'your_secure_secret_key', // Replace with a strong secret
    resave: false,
    saveUninitialized: false,
  }));

  // Example on redirecting user to Google's OAuth 2.0 server.
  app.get('/', async (req, res) => {
    // Generate a secure random state value.
    const state = crypto.randomBytes(32).toString('hex');
    // Store state in the session
    req.session.state = state;

    // 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,
      // Include the state parameter to reduce the risk of CSRF attacks.
      state: state
    });

    res.redirect(authorizationUrl);
  });

  // Receive the callback from Google's OAuth 2.0 server.
  app.get('/oauth2callback', async (req, res) => {
    // 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 if (q.state !== req.session.state) { //check state value
      console.log('State mismatch. Possible CSRF attack');
      res.end('State mismatch. Possible CSRF attack');
    } 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
  app.get('/revoke', async (req, res) => {
    // 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();
  });


  const server = http.createServer(app);
  server.listen(80);
}
main().catch(console.error);

HTTP/REST

この Python の例では Flask フレームワークを使用します。 Requests ライブラリを使用して、実際の OAuth 2.0 と 2.0 ウェブフロー。このフローでは、Python 用 Google API クライアント ライブラリを使用することをおすすめします。( クライアント ライブラリを使用しています)。

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:
    state = str(uuid.uuid4())
    flask.session['state'] = state
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}&state={}').format(CLIENT_ID, REDIRECT_URI,
                                                                          SCOPE, state)
    return flask.redirect(auth_uri)
  else:
    if 'state' not in flask.request.args or flask.request.args['state'] != flask.session['state']:
      return 'State mismatch. Possible CSRF attack.', 400

    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 以下に説明する、domain、host、path、query、scheme、userinfo の定義を参照してください。

検証規則
スキーム

リダイレクト URI には、通常の HTTP ではなく HTTPS スキームを使用する必要があります。ローカルホストの URI( localhost IP アドレス URI など)はすべて、このルールから除外されます。

ホスト

ホストを未加工の IP アドレスにすることはできません。ローカルホストの IP アドレスはこのルールから除外されます。

ドメイン
  • ホスト TLD (トップレベル ドメインpublic サフィックス リストに属している必要があります。
  • ホストドメインを “googleusercontent.com” にすることはできません。
  • リダイレクト URI に、短縮 URL のドメイン(goo.gl など)を含めることはできません。ただし、 アプリがドメインを所有している。さらに、短縮ドメインを所有するアプリが 使用する場合は、そのリダイレクト URI に パス内または末尾が “/google-callback/” “/google-callback”
  • ユーザー情報

    リダイレクト URI に userinfo サブコンポーネントを含めることはできません。

    [Path]

    リダイレクト URI にパス トラバーサル(ディレクトリ バックトラッキング)を含めることはできません。 “/..”“\..”、またはその URL で表されます。 あります。

    クエリ

    リダイレクト URI に オープン リダイレクト

    Fragment

    リダイレクト URI にフラグメント コンポーネントを含めることはできません。

    文字数 リダイレクト URI には、次のような特定の文字を含めることはできません。
    • ワイルドカード文字('*'
    • 印刷できない ASCII 文字
    • 無効なパーセント エンコード(URL エンコードに従っていないパーセント エンコード) パーセント記号の後に 2 桁の 16 進数)
    • null 文字(エンコードされた NULL 文字(例:%00, %C0%80)

    段階的な認可

    OAuth 2.0 プロトコルでは、アプリからリソースへのアクセス承認がリクエストされます。 スコープによって識別されます。承認のリクエストは、ユーザー エクスペリエンスの観点からベスト プラクティスと考えられています。 リソースにアクセスできます。そのために Google の認可サーバーは 段階的承認をサポートしていますこの機能を使用すると、必要に応じてスコープをリクエストできます。 ユーザーが新しいスコープの権限を付与すると、認証コードが返されます。 は、ユーザーがプロジェクトに付与したすべてのスコープを含むトークンと交換されます。

    たとえば、音楽トラックをサンプリングしてミックスを作成できるアプリでは、 リソースに情報が提供されることになります。おそらく、ログインする人の名前だけでしょう。ただし、 完成したミックスリストを保存すると、Google ドライブへのアクセス権が必要になります。ほとんどの人が目にするでしょう アプリが実際に Google ドライブにアクセスしたときに 必要だったからです。

    この場合、ログイン時にアプリが openid をリクエストする可能性があります。 profile スコープで基本的なログインを実行してから、 最初のリクエスト時に https://www.googleapis.com/auth/drive.file スコープで作成されます。 あります

    増分認可を実装するには、アクセスをリクエストする通常のフローを完了します。 ただし、以前に付与されたスコープが認可リクエストに含まれていることを確認してください。この アプローチにより、アプリで複数のアクセス トークンを管理する必要がなくなります。

    増分認可から取得したアクセス トークンには、次のルールが適用されます。

    • このトークンを使用して、サービス アカウントにロールされているスコープに対応するリソースにアクセスできます。 組み合わせて使用します。
    • 複合認証の更新トークンを使用してアクセス トークンを取得すると、 アクセス トークンは、結合された承認を表し、任意のトークンに レスポンスには scope 値が含まれています。
    • 統合された承認には、ユーザーが API プロジェクトに付与したすべてのスコープが含まれます。 異なるクライアントからリクエストされた場合。たとえば、ユーザーがサービス アカウントに アプリケーションのデスクトップ クライアントを使用して別のスコープを付与し、 認証には両方のスコープが含まれることになります。
    • 結合された認可を表すトークンを取り消すと、そのトークンのすべてにアクセスできるようになります。 関連するユーザーの代理承認のスコープが同時に取り消されます。

    「ステップ 1: 認証を設定する」の言語別のコードサンプル パラメータと、ステップ 2: Google の OAuth 2.0 サーバーへのリダイレクトはすべて増分認証を使用します。コードサンプル 以下に、段階的な承認を使用するために追加する必要があるコードも示します。

    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 Cloud リソースにアクセスする必要があるアプリケーションにとって 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_typeoffline に設定 メソッドを使用して更新トークンを受け取ります。アプリに必要な権限をすでに付与している場合 更新トークンを受信するための適切な制約を設定せずに、 アプリケーションを再承認して新しい更新トークンを受け取る

    後で 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 回 全クライアントでユーザーごとに 1 つずつ 異なる組み合わせで作成できます更新トークンを保存する必要がある 保持され、有効な間は継続して使用できます。アプリケーションで リクエストが多すぎると、これらの上限に達する可能性があります。その場合、古い更新トークン 動作しなくなります。

    トークンの取り消し

    アプリケーションに付与したアクセス権の取り消しをユーザーが希望する場合があります。ユーザーはアクセス権を取り消すことができます <ph type="x-smartling-placeholder"></ph>にアクセス アカウント設定。詳しくは、 削除 第三者のサイトやアプリの [サイトまたはアプリのアクセス] セクションでアカウントにアクセスできるアプリ サポート ドキュメントをご覧ください。

    また、アプリケーションに付与されているアクセス権をプログラムで取り消すこともできます。 プログラムによる取り消しは、ユーザーが登録解除を行ったり、 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 リクエストを送信します。 endpoint:

    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 リクエストを行います。 endpoint:

    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 が返されます。 エラーコードが表示されます