OpenID Connect

Google の OAuth 2.0 API は、認証と承認の両方に使用できます。このドキュメントでは、認証用の OAuth 2.0 実装について説明します。この実装は OpenID Connect 仕様に準拠しており、OpenID Certified を受けています。OAuth 2.0 を使用して Google API にアクセスするに記載されているドキュメントも、このサービスに適用されます。このプロトコルをインタラクティブに確認するには、Google OAuth 2.0 Playground を使用することをおすすめします。Stack Overflow でサポートを受けるには、質問に「google-oauth」タグを付けて投稿してください。

OAuth 2.0 の設定

アプリケーションでユーザーのログインに Google の OAuth 2.0 認証システムを使用するには、 Google API Console でプロジェクトを設定して OAuth 2.0 認証情報を取得し、リダイレクト URI を設定し、必要に応じてユーザー同意画面に表示されるブランディング情報をカスタマイズする必要があります。 API Console を使用して、サービス アカウントの作成、課金の有効化、フィルタリング設定などのタスクを実行することもできます。詳しくは、Google API Consoleのヘルプをご覧ください。

OAuth 2.0 認証情報を取得する

ユーザーを認証して Google の API にアクセスするには、クライアント ID やクライアント シークレットなどの OAuth 2.0 認証情報が必要です。

特定のOAuth 2.0認証情報のクライアントIDとクライアントシークレットを表示するには、次のテキストをクリックします認証情報を選択 。開いたウィンドウで、プロジェクトと必要な認証情報を選択し、[ 表示 ]をクリックします

または、 API Console [ 認証情報]ページからクライアントIDとクライアントシークレットを表示しAPI Console 。

  1. Go to the Credentials page.
  2. 資格情報の名前または鉛筆( )アイコンをクリックします。クライアントIDとシークレットはページの上部にあります。

リダイレクト URI を設定する

API Console で設定したリダイレクト URI によって、認証リクエストに対するレスポンスの送信先が決まります。

要创建,查看或编辑给定OAuth 2.0凭据的重定向URI,请执行以下操作:

  1. Go to the Credentials page.
  2. 在页面的OAuth 2.0客户端ID部分中,点击一个凭据。
  3. 查看或编辑重定向URI。

如果“凭据”页面上没有OAuth 2.0客户端ID部分,则您的项目没有OAuth凭据。要创建一个,点击创建凭证

ユーザーの同意画面をカスタマイズする

OAuth 2.0 認証では、ユーザーが公開する情報と適用される利用規約を説明する同意画面が表示されます。たとえば、ユーザーがログインするときに、メールアドレスと基本的なアカウント情報へのアクセスをアプリに許可するよう求められる場合があります。この情報へのアクセスをリクエストするには、scope パラメータを使用します。このパラメータは、アプリの認証リクエストに含めます。スコープを使用して、他の Google API へのアクセスをリクエストすることもできます。

ユーザーの同意画面には、プロダクト名、ロゴ、ホームページの URL などのブランド情報も表示されます。ブランド情報は API Consoleで管理します。

プロジェクトの同意画面を有効にするには:

  1. Consent Screen pageでGoogle API Consoleます。
  2. If prompted, select a project, or create a new one.
  3. フォームに入力して[ 保存 ]をクリックします

次の同意ダイアログは、リクエストに OAuth 2.0 スコープと Google ドライブ スコープの組み合わせが含まれている場合にユーザーに表示される内容を示しています。(この汎用ダイアログは Google OAuth 2.0 Playground を使用して生成されたため、 API Consoleに設定されるブランド情報は含まれていません)。

同意ページのスクリーンショット

サービスへのアクセス

Google とサードパーティは、ユーザーの認証と Google API へのアクセスの取得に関する実装の詳細の多くを処理するために使用できるライブラリを提供しています。たとえば、さまざまなプラットフォームで利用可能な Google Identity ServicesGoogle クライアント ライブラリなどがあります。

ライブラリを使用しない場合は、このドキュメントの残りの手順に沿って操作します。このドキュメントでは、利用可能なライブラリの基盤となる HTTP リクエスト フローを説明します。

ユーザーの認証

ユーザーの認証には、ID トークンの取得と検証が含まれます。 ID トークンは、インターネットで ID アサーションを共有するために設計された OpenID Connect の標準化された機能です。

ユーザーの認証と ID トークンの取得に最もよく使用されるアプローチは、「サーバー」フローおよび「暗黙的」フローと呼ばれます。サーバーフローでは、アプリケーションのバックエンド サーバーがブラウザまたはモバイル デバイスを使用しているユーザーの ID を検証できます。暗黙的なフローを使用するのは、クライアントサイド アプリケーション(通常はブラウザで実行される JavaScript アプリ)が、バックエンド サーバー経由ではなく API に直接アクセスする必要がある場合です。

このドキュメントでは、ユーザーの認証を行うサーバーフローを実行する方法について説明します。暗黙的なフローでは、クライアントサイドでトークンを処理して使用する際にセキュリティ リスクがあるため、はるかに複雑になります。暗黙的なフローを実装する必要がある場合は、Google Identity Services を使用することを強くおすすめします。

サーバー フロー

これらのプロトコルを使用してユーザーを認証できるように、 API Consoleでアプリをセットアップしてください。ユーザーが Google でログインしようとしたときに、次のことを行う必要があります。

  1. なりすまし防止状態トークンを作成する
  2. Google に認証リクエストを送信する
  3. なりすまし防止状態トークンを確認する
  4. code をアクセス トークンと ID トークンと交換する
  5. ID トークンからユーザー情報を取得する
  6. お客様の認証を行う

1. なりすまし防止状態トークンを作成する

リクエストのなりすまし攻撃を防ぐことで、ユーザーのセキュリティを保護する必要があります。最初のステップは、アプリとユーザーのクライアント間で状態を保持する一意のセッション トークンを作成することです。後で、この一意のセッション トークンを Google OAuth ログイン サービスから返された認証レスポンスと照合して、リクエストを送信しているのがユーザーであり、悪意のある攻撃者ではないことを確認します。これらのトークンは、クロスサイト リクエスト フォージェリ(CSRF)トークンとも呼ばれます。

状態トークンには、高品質の乱数ジェネレータを使用して作成された 30 文字程度の文字列が適しています。もう 1 つは、バックエンドで秘密に保持されている鍵を使用してセッション状態変数の一部に署名することで生成されるハッシュです。

次のコードは、一意のセッション トークンの生成を示しています。

PHP

このサンプルを使用するには、PHP 用の Google API クライアント ライブラリをダウンロードする必要があります。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
$state = bin2hex(random_bytes(128/8));
$app['session']->set('state', $state);
// Set the client ID, token state, and application name in the HTML while
// serving it.
return $app['twig']->render('index.html', array(
    'CLIENT_ID' => CLIENT_ID,
    'STATE' => $state,
    'APPLICATION_NAME' => APPLICATION_NAME
));

Java

このサンプルを使用するには、Java 用 Google API クライアント ライブラリをダウンロードする必要があります。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.session().attribute("state", state);
// Read index.html into memory, and set the client ID,
// token state, and application name in the HTML before serving it.
return new Scanner(new File("index.html"), "UTF-8")
    .useDelimiter("\\A").next()
    .replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID)
    .replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
    .replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}",
    APPLICATION_NAME);

Python

このサンプルを使用するには、Python 用 Google API クライアント ライブラリをダウンロードする必要があります。

# Create a state token to prevent request forgery.
# Store it in the session for later validation.
state = hashlib.sha256(os.urandom(1024)).hexdigest()
session['state'] = state
# Set the client ID, token state, and application name in the HTML while
# serving it.
response = make_response(
    render_template('index.html',
                    CLIENT_ID=CLIENT_ID,
                    STATE=state,
                    APPLICATION_NAME=APPLICATION_NAME))

2. Google に認証リクエストを送信する

次のステップでは、適切な URI パラメータを使用して HTTPS GET リクエストを作成します。このプロセスのすべてのステップで HTTP ではなく HTTPS を使用していることに注意してください。HTTP 接続は拒否されます。ベース URI は、authorization_endpoint メタデータ値を使用してディスカバリ ドキュメントから取得する必要があります。以降の説明では、ベース URI が https://accounts.google.com/o/oauth2/v2/auth であることを前提としています。

基本的なリクエストの場合は、次のパラメータを指定します。

  • client_id。 API Console Credentials pageから取得します。
  • response_type。基本的な認証コードフロー リクエストでは code にする必要があります。(詳しくは、response_type をご覧ください)。
  • scope。基本リクエストでは openid email にする必要があります。(詳しくは、scope をご覧ください)。
  • redirect_uri は、Google からのレスポンスを受信するサーバー上の HTTP エンドポイントにする必要があります。この値は、 API Console Credentials pageで構成した OAuth 2.0 クライアントの承認済みリダイレクト URI のいずれかと完全に一致する必要があります。この値が承認済み URI と一致しない場合、リクエストは失敗し、redirect_uri_mismatch エラーが返されます。
  • state には、なりすまし防止の一意のセッション トークンの値と、ユーザーがアプリに戻ったときのコンテキストを復元するために必要なその他の情報(開始 URL など)を含める必要があります。(詳しくは、state をご覧ください)。
  • nonce は、アプリによって生成されるランダムな値で、存在する場合はリプレイ保護を有効にします。
  • login_hint には、ユーザーのメールアドレスまたは sub 文字列(ユーザーの Google ID と同等)を指定できます。login_hint を指定しない場合、ユーザーが現在ログインしている場合は、同意画面に、ユーザーのメールアドレスをアプリに公開するための承認リクエストが含まれます。login_hint をご覧ください。
  • hd パラメータを使用して、Google Workspace または Cloud 組織に関連付けられた特定のドメインのユーザー向けに OpenID Connect フローを最適化します(詳細については、hd をご覧ください)。

読みやすくするため改行とスペースを追加した、完全な OpenID Connect 認証 URI の例を次に示します。

https://accounts.google.com/o/oauth2/v2/auth?
 response_type=code&
 client_id=424911365001.apps.googleusercontent.com&
 scope=openid%20email&
 redirect_uri=https%3A//oauth2.example.com/code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2-login-demo.example.com%2FmyHome&
 login_hint=jsmith@example.com&
 nonce=0394852-3190485-2490358&
 hd=example.com

アプリがユーザーに関する新しい情報をリクエストする場合や、ユーザーが以前に承認していないアカウントへのアクセスをリクエストする場合は、ユーザーの同意が必要です。

3. なりすまし防止状態トークンを確認する

レスポンスは、リクエストで指定した redirect_uri に送信されます。すべてのレスポンスは、次のようにクエリ文字列で返されます。

https://oauth2.example.com/code?state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foa2cb.example.com%2FmyHome&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&scope=openid%20email%20https://www.googleapis.com/auth/userinfo.email

サーバーでは、Google から受信した state が、ステップ 1 で作成したセッション トークンと一致していることを確認する必要があります。このラウンドトリップ検証により、リクエストを送信しているのが悪意のあるスクリプトではなくユーザーであることを確認できます。

次のコードは、手順 1 で作成したセッション トークンを確認する方法を示しています。

PHP

このサンプルを使用するには、PHP 用の Google API クライアント ライブラリをダウンロードする必要があります。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
  return new Response('Invalid state parameter', 401);
}

Java

このサンプルを使用するには、Java 用 Google API クライアント ライブラリをダウンロードする必要があります。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if (!request.queryParams("state").equals(
    request.session().attribute("state"))) {
  response.status(401);
  return GSON.toJson("Invalid state parameter.");
}

Python

このサンプルを使用するには、Python 用 Google API クライアント ライブラリをダウンロードする必要があります。

# Ensure that the request is not a forgery and that the user sending
# this connect request is the expected user.
if request.args.get('state', '') != session['state']:
  response = make_response(json.dumps('Invalid state parameter.'), 401)
  response.headers['Content-Type'] = 'application/json'
  return response

4. code をアクセス トークンと ID トークンと交換する

レスポンスには、code パラメータ(サーバーがアクセス トークンと ID トークンと交換できるワンタイム認証コード)が含まれます。サーバーは、HTTPS POST リクエストを送信することで、この交換を行います。POST リクエストはトークン エンドポイントに送信されます。トークン エンドポイントは、token_endpoint メタデータ値を使用してディスカバリ ドキュメントから取得する必要があります。以降の説明では、エンドポイントが https://oauth2.googleapis.com/token であることを前提としています。リクエストの POST 本文には、次のパラメータを含める必要があります。

フィールド
code 最初のリクエストから返された認証コード。
client_id OAuth 2.0 認証情報を取得するで説明されているように、 API Console Credentials pageから取得したクライアント ID。
client_secret OAuth 2.0 認証情報を取得するの説明に従って、 API Console Credentials pageから取得したクライアント シークレット。
redirect_uri リダイレクト URI を設定するで説明されているように、 API Console Credentials pageで指定された特定の client_id の承認済みリダイレクト URI。
grant_type このフィールドには、 OAuth 2.0 仕様で定義されている authorization_code の値を指定する必要があります。

実際のリクエストは次のようになります。

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

このリクエストに成功すると、JSON 配列に次のフィールドが含まれます。

フィールド
access_token Google API に送信できるトークン。
expires_in アクセス トークンの残り有効期間(秒単位)。
id_token Google によってデジタル署名されたユーザーの ID 情報を含む JWT
scope access_token によって付与されるアクセス スコープ。スペース区切りの大文字と小文字を区別する文字列のリストとして表されます。
token_type 返されるトークンのタイプを識別します。現時点では、このフィールドの値は常に Bearer です。
refresh_token (省略可)

このフィールドは、認証リクエストaccess_type パラメータが offline に設定されている場合にのみ存在します。詳しくは、更新トークンをご覧ください。

5. ID トークンからユーザー情報を取得する

ID トークンは JWT(JSON Web Token)です。つまり、暗号署名付きの Base64 エンコード JSON オブジェクトです。通常、ID トークンを使用する前にID トークンを検証することが重要ですが、この場合は、仲介なしの HTTPS チャネルを介して Google と直接通信し、クライアント シークレットを使用して Google に対して自身を認証するため、受信したトークンが本当に Google からのものであり、有効であることを確信できます。サーバーが ID トークンをアプリの他のコンポーネントに渡す場合は、他のコンポーネントがトークンを使用する前にトークンを検証することが非常に重要です。

ほとんどの API ライブラリでは、検証と base64url でエンコードされた値のデコードと JSON の解析が組み合わされているため、ID トークンのクレームにアクセスするときにトークンを検証することになります。

ID トークンのペイロード

ID トークンは、名前と値のペアのセットを含む JSON オブジェクトです。読みやすくするためにフォーマットした例を次に示します。

{
  "iss": "https://accounts.google.com",
  "azp": "1234987819200.apps.googleusercontent.com",
  "aud": "1234987819200.apps.googleusercontent.com",
  "sub": "10769150350006150715113082367",
  "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
  "hd": "example.com",
  "email": "jsmith@example.com",
  "email_verified": "true",
  "iat": 1353601026,
  "exp": 1353604926,
  "nonce": "0394852-3190485-2490358"
}

Google ID トークンには次のフィールド(クレームと呼ばれる)が含まれる場合があります。

申し立て 提供 説明
aud 常に この ID トークンの対象となるオーディエンス。アプリケーションの OAuth 2.0 クライアント ID のいずれかにする必要があります。
exp 常に ID トークンの受け入れが拒否される有効期限。Unix 時間(整数秒)で表されます。
iat 常に ID トークンが発行された時刻。Unix 時間(整数秒)で表されます。
iss 常に レスポンス発行者の発行者 ID。Google ID トークンの場合は、常に https://accounts.google.com または accounts.google.com です。
sub 常に ユーザーの ID。すべての Google アカウントに固有で、決して再利用されません。1 つの Google アカウントに異なる時点で複数のメールアドレスを設定できますが、sub 値は変更されません。sub をアプリケーション内でユーザーの一意の ID キーとして使用します。最大長は 255 文字(大文字と小文字を区別)。
at_hash アクセス トークンのハッシュ。アクセス トークンが ID トークンに関連付けられていることを検証します。サーバー フローで access_token 値を使用して ID トークンが発行された場合、このクレームは常に含まれます。このクレームは、クロスサイト リクエスト フォージェリ攻撃を防ぐための代替メカニズムとして使用できますが、ステップ 1ステップ 3 に沿って操作すれば、アクセス トークンを検証する必要はありません。
azp 承認済みのプレゼンターの client_id。このクレームは、ID トークンをリクエストしている当事者が ID トークンのオーディエンスと同じでない場合にのみ必要になります。これは、Google のハイブリッド アプリで、ウェブ アプリケーションと Android アプリの OAuth 2.0 client_id が異なるものの、同じ Google API プロジェクトを共有するケースが考えられます。
email ユーザーのメールアドレスです。リクエストに email スコープが含まれている場合にのみ提供されます。このクレームの値は、このアカウントに固有のものではなく、時間の経過とともに変更される可能性があるため、ユーザー レコードへのリンクに使用するプライマリ ID としてこの値を使用しないでください。また、email クレームのドメインを使用して Google Workspace または Cloud 組織のユーザーを識別することもできません。代わりに hd クレームを使用します。
email_verified ユーザーのメールアドレスが確認済みの場合は true。それ以外の場合は false です。
family_name ユーザーの姓。name クレームが存在する場合に指定される場合があります。
given_name ユーザーの名(ファースト ネーム)。name クレームが存在する場合に指定される場合があります。
hd ユーザーの Google Workspace または Cloud 組織に関連付けられているドメイン。ユーザーが Google Cloud 組織に属している場合にのみ提供されます。リソースへのアクセスを特定のドメインのメンバーのみに制限する場合は、このクレームをチェックする必要があります。このクレームがない場合、アカウントは Google がホストするドメインに属していません。
locale ユーザーのロケール(BCP 47 言語タグで表されます)。name クレームが存在する場合に指定される場合があります。
name 表示可能な形式でのユーザーの氏名。次のような場合に提供される場合があります。
  • リクエスト スコープに「profile」という文字列が含まれている
  • ID トークンがトークンの更新から返される

name クレームが存在する場合は、それを使用してアプリのユーザー レコードを更新できます。このクレームが必ず存在するとは限りません。

nonce 認証リクエストでアプリが提供した nonce の値。確実に 1 回だけ示すことで、リプレイ アタックからの保護を適用する必要があります。
picture ユーザーのプロフィール写真の URL。次のような場合に提供される場合があります。
  • リクエスト スコープに「profile」という文字列が含まれている
  • ID トークンがトークンの更新から返される

picture クレームが存在する場合は、それを使用してアプリのユーザー レコードを更新できます。このクレームが必ず存在するとは限りません。

profile ユーザーのプロフィール ページの URL。次のような場合に提供される場合があります。
  • リクエスト スコープに「profile」という文字列が含まれている
  • ID トークンがトークンの更新から返される

profile クレームが存在する場合は、それを使用してアプリのユーザー レコードを更新できます。このクレームが必ず存在するとは限りません。

6. お客様の認証

ID トークンからユーザー情報を取得したら、アプリのユーザー データベースをクエリする必要があります。ユーザーがデータベースにすでに存在する場合は、Google API レスポンスですべてのログイン要件が満たされている場合は、そのユーザーのアプリケーション セッションを開始する必要があります。

ユーザーがユーザー データベースに存在しない場合、ユーザーを新規ユーザー登録フローにリダイレクトする必要があります。Google から受け取った情報に基づいてユーザーを自動登録できる場合があります。少なくとも、登録フォームに必要な多くのフィールドを事前に入力できる場合があります。ID トークンの情報に加えて、ユーザー プロフィール エンドポイントでユーザー プロフィール情報も取得できます。

高度なトピック

以降のセクションでは、Google OAuth 2.0 API について詳しく説明します。この情報は、認証と認可に関する高度な要件を持つデベロッパーを対象としています。

他の Google API へのアクセス

認証に OAuth 2.0 を使用する利点の一つは、ユーザーの認証と同時に、ユーザーに代わって他の Google API(YouTube、Google ドライブ、カレンダー、連絡先など)を使用する権限をアプリケーションが取得できることです。これを行うには、Google に送信する認証リクエストに、必要な他のスコープを含めます。たとえば、ユーザーの年齢層を認証リクエストに追加するには、スコープ パラメータ openid email https://www.googleapis.com/auth/profile.agerange.read を渡します。同意画面でユーザーに適切なメッセージが表示されます。Google から返されたアクセス トークンを使用すると、リクエストして付与されたアクセス スコープに関連するすべての API にアクセスできます。

更新トークン

API アクセスのリクエストで、code 交換時に返される更新トークンをリクエストできます。更新トークンを使用すると、ユーザーがアプリケーションに存在しない間も、アプリは Google API に継続的にアクセスできます。更新トークンをリクエストするには、認証リクエストaccess_type パラメータを offline に設定します。

考慮事項:

  • 更新トークンは、コード交換フローを初めて実行したときにのみ取得できるため、安全に永続的に保存してください。
  • 発行される更新トークンの数には上限があります。クライアントとユーザーの組み合わせごとに 1 つの上限と、すべてのクライアントのユーザーごとに 1 つの上限です。アプリがリフレッシュ トークンを過度にリクエストすると、これらの上限に達することがあります。その場合、古いリフレッシュ トークンは機能しなくなります。

詳細については、アクセス トークンの更新(オフライン アクセス)をご覧ください。

認証リクエストprompt パラメータを consent に設定すると、アプリの再承認を求めるプロンプトをユーザーに表示できます。prompt=consent が含まれている場合、アプリがアクセス スコープの承認をリクエストするたびに同意画面が表示されます。これは、すべてのスコープが以前に Google APIs プロジェクトに付与されている場合でも同様です。このため、prompt=consent は必要な場合にのみ含めてください。

prompt パラメータの詳細については、認証 URI パラメータの表の prompt をご覧ください。

認証 URI パラメータ

次の表に、Google の OAuth 2.0 認証 API で使用できるパラメータの詳細を示します。

パラメータ 必須 説明
client_id (必須) OAuth 2.0 認証情報を取得するで説明されているように、 API Console Credentials pageから取得したクライアント ID 文字列。
nonce (必須) リプレイ保護を有効にする、アプリによって生成されたランダムな値。
response_type (必須) 値が code の場合、基本認可コードフローが開始され、トークンを取得するためにトークン エンドポイントへの POST が必要になります。値が token id_token または id_token token の場合、暗黙的なフローが開始されます。この場合、リダイレクト URI で JavaScript を使用して URI #fragment ID からトークンを取得する必要があります。
redirect_uri (必須) レスポンスの送信先を決定します。このパラメータの値は、 API Console Credentials page で設定した承認済みリダイレクト値のいずれかと完全に一致する必要があります(HTTP または HTTPS スキーム、大文字と小文字、末尾の「/」を含みます)。
scope (必須)

スコープ パラメータは openid 値で始め、profile 値、email 値、またはその両方を含める必要があります。

profile スコープ値が存在する場合、ID トークンにユーザーのデフォルトの profile クレームが含まれることがあります(必ずしも含まれるとは限りません)。

email スコープ値が存在する場合、ID トークンには email クレームと email_verified クレームが含まれます。

これらの OpenID 固有のスコープに追加して、他のスコープ値をスコープ引数に含めることもできます。スコープ値はすべてスペースで区切る必要があります。たとえば、ユーザーの Google ドライブにファイルごとにアクセスする場合、スコープ パラメータは openid profile email https://www.googleapis.com/auth/drive.file になります。

使用可能なスコープについては、Google API の OAuth 2.0 スコープまたは使用する Google API のドキュメントをご覧ください。

state (省略可ですが、強く推奨します)

プロトコルでラウンドトリップされる不透明な文字列。つまり、基本フローでは URI パラメータとして、暗黙フローでは URI #fragment 識別子として返されます。

state は、リクエストとレスポンスを関連付けるのに役立ちます。 redirect_uri は推測される可能性があるため、state 値を使用すると、受信接続がアプリによって開始された認証リクエストの結果であることをより確実にできます。この state 変数にランダムな文字列を生成するか、クライアント状態(Cookie など)のハッシュをエンコードすると、レスポンスを検証して、リクエストとレスポンスが同じブラウザで発生したことをさらに確認できます。これにより、クロスサイト リクエスト フォージェリなどの攻撃から保護されます。

access_type (省略可) 指定できる値は offlineonline です。この効果については、オフライン アクセスで説明しています。アクセス トークンがリクエストされている場合、offline の値が指定されていない限り、クライアントは更新トークンを受け取りません。
display (省略可) 認可サーバーが認証と同意のユーザー インターフェース ページを表示する方法を指定するための ASCII 文字列値。次の値は指定され、Google サーバーで受け入れられますが、動作には影響しません。pagepopuptouchwap
hd (省略可)

Google Cloud 組織が所有するアカウントのログイン プロセスを効率化します。Google Cloud 組織のドメイン(mycollege.edu など)を含めると、アカウント選択 UI をそのドメインのアカウント用に最適化する必要があります。1 つの Google Cloud 組織ドメインではなく、Google Cloud 組織アカウント全体を最適化するには、アスタリスク(*)の値(hd=*)を設定します。

クライアントサイド リクエストは変更される可能性があるため、この UI 最適化に依存してアプリにアクセスできるユーザーを制御しないでください。返された ID トークンに、想定どおりの hd クレーム値(mycolledge.edu など)が含まれていることを検証してください。リクエスト パラメータとは異なり、ID トークンの hd クレームは Google のセキュリティ トークン内に含まれているため、値は信頼できます。

include_granted_scopes (省略可) このパラメータに値 true を指定して承認リクエストが承認されると、このユーザー/アプリケーションの組み合わせに他のスコープで付与された以前の承認が含まれます。増分承認をご覧ください。

インストール済みアプリのフローでは、増分認可を行うことはできません。

login_hint (省略可) アプリが認証しようとしているユーザーを把握している場合は、このパラメータを認証サーバーにヒントとして提供できます。このヒントを渡すと、アカウント選択ツールが抑制され、ログイン フォームのメールボックスが事前入力されるか、適切なセッションが選択されます(ユーザーがマルチログインを使用している場合)。これにより、アプリが間違ったユーザー アカウントにログインした場合に発生する問題を回避できます。値は、メールアドレスまたは sub 文字列(ユーザーの Google ID と同等)のいずれかです。
prompt (省略可) 認可サーバーがユーザーに再認証と同意を求めるかどうかを指定する、スペース区切りの文字列値のリスト。使用できる値は次のとおりです。
  • none

    認可サーバーは、認証画面やユーザーの同意画面を表示しません。ユーザーがまだ認証されておらず、リクエストされたスコープの同意が事前構成されていない場合は、エラーが返されます。none を使用すると、既存の認証や同意を確認できます。

  • consent

    認可サーバーは、クライアントに情報を返す前にユーザーに同意を求めます。

  • select_account

    認可サーバーは、ユーザー アカウントを選択するようユーザーに求めます。これにより、認可サーバーで複数のアカウントを持つユーザーは、現在のセッションがある複数のアカウントから選択できます。

値が指定されておらず、ユーザーがアクセスを承認していない場合は、同意画面が表示されます。

ID トークンの検証

Google から直接送信されたことを確認できない限り、すべての ID トークンをサーバーで検証する必要があります。たとえば、サーバーはクライアント アプリから受信した ID トークンが真正なものであることを確認する必要があります。

ID トークンをサーバーに送信する一般的な状況は次のとおりです。

  • 認証が必要なリクエストとともに ID トークンを送信する。ID トークンには、リクエストを行った特定のユーザーと、その ID トークンが付与されたクライアントが示されます。

ID トークンは機密情報であり、傍受されると不正使用される可能性があります。これらのトークンは、HTTPS 経由でのみ、POST データ経由またはリクエスト ヘッダー内でのみ送信することで、安全に処理されるようにする必要があります。ID トークンをサーバーに保存する場合は、安全に保存する必要があります。

ID トークンが便利な理由の一つは、アプリのさまざまなコンポーネント間で渡すことができる点です。これらのコンポーネントは、アプリとユーザーを認証する軽量な認証メカニズムとして ID トークンを使用できます。ただし、ID トークン内の情報を使用したり、ユーザーが認証したというアサーションとして使用したりするには、その情報を検証する必要があります。

ID トークンの検証には、次の手順が必要です。

  1. ID トークンが発行元によって適切に署名されていることを確認します。Google が発行したトークンは、ディスカバリ ドキュメントjwks_uri メタデータ値で指定された URI にある証明書のいずれかを使用して署名されます。
  2. ID トークンの iss クレームの値が https://accounts.google.com または accounts.google.com と等しいことを確認します。
  3. ID トークンの aud クレームの値がアプリのクライアント ID と一致していることを確認します。
  4. ID トークンの有効期限(exp クレーム)が切れていないことを確認します。
  5. リクエストで hd パラメータの値を指定した場合は、ID トークンに、Google Cloud 組織に関連付けられている承認済みドメインと一致する hd クレームがあることを確認します。

ステップ 2 ~ 5 では、文字列と日付の比較のみが行われます。これは非常に簡単な処理であるため、ここでは詳細を説明しません。

最初のステップはより複雑で、暗号署名のチェックが含まれます。デバッグ目的で、Google の tokeninfo エンドポイントを使用して、サーバーまたはデバイスに実装されたローカル処理と比較できます。ID トークンの値が XYZ123 であるとします。次に、URI https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123 を参照解除します。トークン署名が有効な場合、レスポンスはデコードされた JSON オブジェクト形式の JWT ペイロードになります。

tokeninfo エンドポイントはデバッグに役立ちますが、本番環境では、鍵エンドポイントから Google の公開鍵を取得し、ローカルで検証を実行します。鍵の URI は、jwks_uri メタデータ値を使用してディスカバリ ドキュメントから取得する必要があります。デバッグ エンドポイントへのリクエストは、スロットリングされるか、断続的なエラーが発生する可能性があります。

Google は公開鍵を頻繁に変更しないため、HTTP レスポンスのキャッシュ ディレクティブを使用して公開鍵をキャッシュに保存できます。ほとんどの場合、tokeninfo エンドポイントを使用するよりもローカル検証を効率的に実行できます。この検証では、証明書の取得と解析、適切な暗号呼び出しによる署名の確認が必要です。幸い、この目的を達成するために、さまざまな言語でデバッグ済みのライブラリが利用できます(jwt.io をご覧ください)。

ユーザー プロフィール情報の取得

ユーザーに関する追加のプロファイル情報を入手するには、アクセス トークン(アプリケーションが認証フローで受け取る)と OpenID Connect 標準を使用できます。

  1. OpenID に準拠するには、認証リクエストopenid profile スコープ値を含める必要があります。

    ユーザーのメールアドレスを含めたい場合は、追加のスコープ値 email を指定できます。profileemail の両方を指定するには、認証リクエスト URI に次のパラメータを含めます。

    scope=openid%20profile%20email
  2. アクセス トークンを承認ヘッダーに追加し、ユーザー情報エンドポイントに HTTPS GET リクエストを送信します。ユーザー情報エンドポイントは、userinfo_endpoint メタデータ値を使用してディスカバリ ドキュメントから取得する必要があります。ユーザー情報の回答にはユーザーに関する情報が含まれます。この情報は、OpenID Connect Standard Claims とディスカバリ ドキュメントの claims_supported メタデータ値に記述されているとおりです。ユーザーまたはユーザーの組織は、特定の項目に情報を提供したり、しなかったりするため、パートナー様がアクセスを許可されているスコープのすべての項目に対する情報を得られるとは限りません。

ディスカバリ ドキュメント

OpenID Connect プロトコルでは、ユーザーの認証と、トークン、ユーザー情報、公開鍵などのリソースのリクエストに複数のエンドポイントを使用する必要があります。

実装を簡素化し、柔軟性を高めるために、OpenID Connect では「ディスカバリ ドキュメント」を使用できます。これは、よく知られた場所にある JSON ドキュメントで、OpenID Connect プロバイダの構成に関する詳細(認可、トークン、取り消し、ユーザー情報、公開鍵エンドポイントの URI など)を提供する Key-Value ペアが含まれています。Google の OpenID Connect サービスの Discovery ドキュメントは、次の場所から取得できます。

https://accounts.google.com/.well-known/openid-configuration

Google の OpenID Connect サービスを使用するには、ディスカバリ ドキュメントの URI(https://accounts.google.com/.well-known/openid-configuration)をアプリケーションにハードコードする必要があります。アプリケーションはドキュメントを取得し、レスポンスにキャッシュ ルールを適用してから、必要に応じてエンドポイント URI を取得します。たとえば、ユーザーを認証するために、コードは Google に送信される認証リクエストのベース URI として authorization_endpoint メタデータ値(以下の例では https://accounts.google.com/o/oauth2/v2/auth)を取得します。

このようなドキュメントの例を次に示します。フィールド名は OpenID Connect Discovery 1.0 で指定されているものです(意味については、そのドキュメントをご覧ください)。以下の値はあくまでも例示であり、実際の Google ディスカバリー ドキュメントの最新バージョンからコピーしたものですが、変更される可能性があります。

{
  "issuer": "https://accounts.google.com",
  "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
  "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
  "token_endpoint": "https://oauth2.googleapis.com/token",
  "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
  "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "code token",
    "code id_token",
    "token id_token",
    "code token id_token",
    "none"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "scopes_supported": [
    "openid",
    "email",
    "profile"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "claims_supported": [
    "aud",
    "email",
    "email_verified",
    "exp",
    "family_name",
    "given_name",
    "iat",
    "iss",
    "locale",
    "name",
    "picture",
    "sub"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

Discovery ドキュメントの値をキャッシュに保存することで、HTTP ラウンドトリップを回避できる場合があります。標準の HTTP キャッシュ ヘッダーが使用され、その指示に従う必要があります。

クライアント ライブラリ

次のクライアント ライブラリを使用すると、一般的なフレームワークと統合することで、OAuth 2.0 の実装が簡単になります。

OpenID Connect コンプライアンス

Google の OAuth 2.0 認証システムは、OpenID Connect Core 仕様の必須機能をサポートしています。OpenID Connect と連携するように設計されたクライアントは、このサービスと相互運用する必要があります(OpenID リクエスト オブジェクトを除く)。