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 によって、Google が認証リクエストにレスポンスを送信する場所が決まります。

特定の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 ログインGoogle クライアント ライブラリなど、さまざまなプラットフォームで利用できます。

ライブラリを使用しない場合は、このドキュメントで後述する手順に沿ってください。ここでは、使用可能なライブラリの基礎となる HTTP リクエスト フローについて説明します。

ユーザーの認証

ユーザーの認証には、ID トークンを取得して検証する必要があります。ID トークンは、OpenID Connect の標準機能であり、インターネット上で ID アサーションを共有するために使用できます。

ユーザーの認証と ID トークンの取得に使用される最も一般的な方法は、「サーバーフロー」と「暗黙的フロー」です。サーバー フローでは、アプリケーションのバックエンド サーバーがブラウザやモバイル デバイスを使用して個人の本人確認を行えます。暗黙的フローは、クライアント側アプリケーション(通常はブラウザで実行されている JavaScript アプリ)がバックエンド サーバーを経由せずに API に直接アクセスする必要がある場合に使用されます。

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

サーバーフロー

これらのプロトコルを使用してユーザーを認証できるように、 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 接続は拒否されます。authorization_endpoint メタデータ値を使用して、ディスカバリ ドキュメントからベース URI を取得する必要があります。以下の説明では、ベース URI は https://accounts.google.com/o/oauth2/v2/auth であることを前提としています。

基本リクエストでは、以下のパラメータを指定します。

  • client_id。これは、 API ConsoleCredentials page.
  • response_type。基本的な認証コードフロー リクエストでは code になります。(詳しくは response_type をご覧ください)。
  • scope。基本リクエストでは openid email にする必要があります。(詳しくは scope をご覧ください)。
  • redirect_uri は、Google からのレスポンスを受信するサーバーの HTTP エンドポイントである必要があります。この値は、 Credentials pageで構成した OAuth 2.0 クライアントの承認済みのリダイレクト URI のいずれかと正確に一致している必要があります。 API Consoleこの値が承認済みの URI と一致しない場合、リクエストは失敗し、redirect_uri_mismatch エラーが発生します。
  • state には、偽造防止の一意のセッション トークンの値と、ユーザーがアプリケーションに戻ったときにコンテキストを復元するために必要な他の情報(開始 URL など)を含める必要があります。(詳しくは state をご覧ください)。
  • nonce は、アプリによって生成されたランダムな値で、存在する場合にリプレイ保護を有効にします。
  • login_hint には、ユーザーのメールアドレスまたは sub 文字列(ユーザーの Google ID と同等)を指定できます。login_hint を提供しておらず、ユーザーが現在ログインしている場合、同意画面には、ユーザーのメールアドレスをアプリに解放するための承認リクエストが含まれます。詳しくは、login_hint をご覧ください。
  • hd パラメータを使用して、Google 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 トークンに交換できる 1 回限りの認証コードです。サーバーは HTTPS POST リクエストを送信して、この交換を行います。POST リクエストがトークン エンドポイントに送信されます。このトークンは、token_endpoint メタデータ値を使用して、ディスカバリ ドキュメントから取得する必要があります。以下の説明では、エンドポイントが https://oauth2.googleapis.com/token であることを前提としています。リクエストでは、POST 本文に次のパラメータを含める必要があります。

フィールド
code 最初のリクエストから返される認証コード。
client_id Credentials pageから取得したクライアント ID。 API ConsoleOAuth 2.0 認証情報を取得するをご覧ください。
client_secret Credentials pageから取得するクライアント シークレット。OAuth 2.0 認証情報を取得するをご覧ください。 API Console
redirect_uri リダイレクト URI を設定するの説明に沿って、 API ConsoleCredentials 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 トークンを検証することが重要です。ただし、中間の 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 トークンには、次のフィールド(クレーム)を含めることができます。

請求 指定のクレジット カード Description
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 を、ユーザーの一意の識別子キーとして使用します。ASCII 文字で最大 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 スコープ値が含まれている場合のみ提供されます。
email_verified ユーザーのメールアドレスが確認された場合は true、それ以外の場合は false。
family_name お客様の姓または名。name クレームが存在する場合に提供される場合があります。
given_name ユーザーの名(ファースト ネーム)。name クレームが存在する場合に提供される場合があります。
hd ユーザーの Google Cloud 組織に関連付けられているドメイン。ユーザーが Google Cloud 組織に属している場合にのみ提供されます。
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 を使用するメリットの 1 つは、ユーザー認証と同時に、他の Google API(YouTube、Google ドライブ、カレンダー、コンタクトなど)を代理でアプリケーションで使用する権限を取得できることです。これを行うには、Google に送信する認証リクエストに必要な他のスコープを含めます。たとえば、ユーザーの年齢グループを認証リクエストに追加するには、スコープ パラメータ openid email https://www.googleapis.com/auth/profile.agerange.read を渡します。ユーザーが同意画面で適切に表示されます。Google から受け取ったアクセス トークンを使用して、リクエストしたアクセス スコープに関連するすべての API にアクセスできます。

リフレッシュ トークン

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

考慮事項:

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

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

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

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

認証 URI パラメータ

次の表は、Google の OAuth 2.0 認証 API で使用できるパラメータについて詳しく説明しています。

パラメータ 必須 Description
client_id (必須) API ConsoleCredentials pageから取得したクライアント ID の文字列。OAuth 2.0 の認証情報の取得をご覧ください。
nonce (必須) リプレイ保護を有効にするアプリによって生成されたランダムな値。
response_type (必須) 値が code の場合、基本認証コードフローが起動します。トークンを取得するには、トークン エンドポイントへの POST が必要です。値が token id_token または id_token token の場合、暗黙的フローを起動し、リダイレクト URI で JavaScript を使用して URI #fragment 識別子からトークンを取得します。
redirect_uri (必須) レスポンスの送信先を指定します。このパラメータの値は、 API ConsoleCredentials 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 (省略可能ですが強くおすすめします)

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

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

access_type (省略可) 指定できる値は offline および online です。この影響については、オフライン アクセスをご覧ください。アクセス トークンがリクエストされている場合、offline の値を指定しないと、クライアントは更新トークンを受け取りません。
display (省略可) 認証サーバーが認証と同意のユーザー インターフェース ページをどのように表示するかを指定する ASCII 文字列値。pagepopuptouchwap は、Google サーバーで指定され、受け入れられますが、動作には影響しません。
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 トークン内の情報を使用したり、ユーザーが認証済みであることを示すアサーションとして 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 トークンの hd クレームが、Google Cloud 組織に関連付けられた承認済みドメインと一致することを確認します。

ステップ 2 ~ 5 では、文字列と日付の比較のみが行われるので、ここでは詳しく説明しません。

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

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

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

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

ユーザーに関する追加のプロフィール情報を取得するには、アクセス トークン(認証フロー中にアプリケーションが受信するアクセス トークン)と OpenID Connect 標準を使用します。

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

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

    scope=openid%20profile%20email
  2. アクセス トークンを承認ヘッダーに追加し、HTTPS GET リクエストを userinfo エンドポイントに対して作成します。このリクエストは、userinfo_endpoint メタデータ値を使用して、ディスカバリ ドキュメントから取得する必要があります。userinfo レスポンスには、ユーザーに関する情報が含まれます。詳細については、OpenID Connect Standard Claims と、ディスカバリ ドキュメントの claims_supported メタデータ値をご覧ください。ユーザーまたはその組織は特定のフィールドを提供または抑制することがあるため、承認されたアクセス スコープについて、すべてのフィールドに関する情報が入手できるとは限りません。

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

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

実装を簡略化し、柔軟性を高めるために、OpenID Connect では「ディスカバリ ドキュメント」を使用できます。これは、Key-Value ペアを含む有名な場所にある JSON ドキュメントで、認証、トークン、取り消し、ユーザー情報、公開鍵のエンドポイントの URI など、OpenID Connect プロバイダの構成の詳細が記載されています。Google の OpenID Connect サービスのディスカバリ ドキュメントは、以下から取得できます。

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 Discovery ドキュメントの最新バージョンからコピーされる場合もあります。

{
  "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 Request オブジェクトを除いて)このサービスと相互運用する必要があります。