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 認証システムを使用するには、 でプロジェクトを設定して OAuth 2.0 認証情報を取得し、リダイレクト URI を設定し、必要に応じてユーザー同意画面に表示されるブランディング情報をカスタマイズする必要があります。 を使用して、サービス アカウントの作成、課金の有効化、フィルタリング設定などのタスクを実行することもできます。詳しくは、のヘルプをご覧ください。
OAuth 2.0 認証情報を取得する
ユーザーを認証して Google の API にアクセスするには、クライアント ID やクライアント シークレットなどの OAuth 2.0 認証情報が必要です。
リダイレクト URI を設定する
で設定したリダイレクト URI によって、認証リクエストに対するレスポンスの送信先が決まります。
ユーザーの同意画面をカスタマイズする
OAuth 2.0 認証では、ユーザーが公開する情報と適用される利用規約を説明する同意画面が表示されます。たとえば、ユーザーがログインするときに、メールアドレスと基本的なアカウント情報へのアクセスをアプリに許可するよう求められる場合があります。この情報へのアクセスをリクエストするには、scope
パラメータを使用します。このパラメータは、アプリの認証リクエストに含めます。スコープを使用して、他の Google API へのアクセスをリクエストすることもできます。
ユーザーの同意画面には、プロダクト名、ロゴ、ホームページの URL などのブランド情報も表示されます。ブランド情報は で管理します。
次の同意ダイアログは、リクエストに OAuth 2.0 スコープと Google ドライブ スコープの組み合わせが含まれている場合にユーザーに表示される内容を示しています。(この汎用ダイアログは Google OAuth 2.0 Playground を使用して生成されたため、 に設定されるブランド情報は含まれていません)。
サービスへのアクセス
Google とサードパーティは、ユーザーの認証と Google API へのアクセスの取得に関する実装の詳細の多くを処理するために使用できるライブラリを提供しています。たとえば、さまざまなプラットフォームで利用可能な Google Identity Services や Google クライアント ライブラリなどがあります。
ライブラリを使用しない場合は、このドキュメントの残りの手順に沿って操作します。このドキュメントでは、利用可能なライブラリの基盤となる HTTP リクエスト フローを説明します。
ユーザーの認証
ユーザーの認証には、ID トークンの取得と検証が含まれます。 ID トークンは、インターネットで ID アサーションを共有するために設計された OpenID Connect の標準化された機能です。
ユーザーの認証と ID トークンの取得に最もよく使用されるアプローチは、「サーバー」フローおよび「暗黙的」フローと呼ばれます。サーバーフローでは、アプリケーションのバックエンド サーバーがブラウザまたはモバイル デバイスを使用しているユーザーの ID を検証できます。暗黙的なフローを使用するのは、クライアントサイド アプリケーション(通常はブラウザで実行される JavaScript アプリ)が、バックエンド サーバー経由ではなく API に直接アクセスする必要がある場合です。
このドキュメントでは、ユーザーの認証を行うサーバーフローを実行する方法について説明します。暗黙的なフローでは、クライアントサイドでトークンを処理して使用する際にセキュリティ リスクがあるため、はるかに複雑になります。暗黙的なフローを実装する必要がある場合は、Google Identity Services を使用することを強くおすすめします。
サーバー フロー
これらのプロトコルを使用してユーザーを認証できるように、 でアプリをセットアップしてください。ユーザーが Google でログインしようとしたときに、次のことを行う必要があります。
- なりすまし防止状態トークンを作成する
- Google に認証リクエストを送信する
- なりすまし防止状態トークンを確認する
code
をアクセス トークンと ID トークンと交換する- ID トークンからユーザー情報を取得する
- お客様の認証を行う
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
。 から取得します。response_type
。基本的な認証コードフロー リクエストではcode
にする必要があります。(詳しくは、response_type
をご覧ください)。scope
。基本リクエストではopenid email
にする必要があります。(詳しくは、scope
をご覧ください)。redirect_uri
は、Google からのレスポンスを受信するサーバー上の HTTP エンドポイントにする必要があります。この値は、 で構成した 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 認証情報を取得するで説明されているように、 から取得したクライアント ID。 |
client_secret |
OAuth 2.0 認証情報を取得するの説明に従って、 から取得したクライアント シークレット。 |
redirect_uri |
リダイレクト URI を設定するで説明されているように、
で指定された特定の 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 |
(省略可)
このフィールドは、認証リクエストで |
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 |
表示可能な形式でのユーザーの氏名。次のような場合に提供される場合があります。
|
|
nonce |
認証リクエストでアプリが提供した nonce の値。確実に 1 回だけ示すことで、リプレイ アタックからの保護を適用する必要があります。 |
|
picture |
ユーザーのプロフィール写真の URL。次のような場合に提供される場合があります。
|
|
profile |
ユーザーのプロフィール ページの URL。次のような場合に提供される場合があります。
|
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 認証情報を取得するで説明されているように、 から取得したクライアント ID 文字列。 |
nonce |
(必須) | リプレイ保護を有効にする、アプリによって生成されたランダムな値。 |
response_type |
(必須) | 値が code の場合、基本認可コードフローが開始され、トークンを取得するためにトークン エンドポイントへの POST が必要になります。値が token id_token または id_token token の場合、暗黙的なフローが開始されます。この場合、リダイレクト URI で JavaScript を使用して URI #fragment ID からトークンを取得する必要があります。 |
redirect_uri |
(必須) | レスポンスの送信先を決定します。このパラメータの値は、 で設定した承認済みリダイレクト値のいずれかと完全に一致する必要があります(HTTP または HTTPS スキーム、大文字と小文字、末尾の「/」を含みます)。 |
scope |
(必須) | スコープ パラメータは
これらの OpenID 固有のスコープに追加して、他のスコープ値をスコープ引数に含めることもできます。スコープ値はすべてスペースで区切る必要があります。たとえば、ユーザーの Google ドライブにファイルごとにアクセスする場合、スコープ パラメータは 使用可能なスコープについては、Google API の OAuth 2.0 スコープまたは使用する Google API のドキュメントをご覧ください。 |
state |
(省略可ですが、強く推奨します) | プロトコルでラウンドトリップされる不透明な文字列。つまり、基本フローでは URI パラメータとして、暗黙フローでは URI
|
access_type |
(省略可) | 指定できる値は offline と online です。この効果については、オフライン アクセスで説明しています。アクセス トークンがリクエストされている場合、offline の値が指定されていない限り、クライアントは更新トークンを受け取りません。 |
display |
(省略可) | 認可サーバーが認証と同意のユーザー インターフェース ページを表示する方法を指定するための ASCII 文字列値。次の値は指定され、Google サーバーで受け入れられますが、動作には影響しません。page 、popup 、touch 、wap 。 |
hd |
(省略可) | Google Cloud 組織が所有するアカウントのログイン プロセスを効率化します。Google Cloud 組織のドメイン(mycollege.edu など)を含めると、アカウント選択 UI をそのドメインのアカウント用に最適化する必要があります。1 つの Google Cloud 組織ドメインではなく、Google Cloud 組織アカウント全体を最適化するには、アスタリスク( クライアントサイド リクエストは変更される可能性があるため、この UI 最適化に依存してアプリにアクセスできるユーザーを制御しないでください。返された ID トークンに、想定どおりの |
include_granted_scopes |
(省略可) | このパラメータに値 true を指定して承認リクエストが承認されると、このユーザー/アプリケーションの組み合わせに他のスコープで付与された以前の承認が含まれます。増分承認をご覧ください。インストール済みアプリのフローでは、増分認可を行うことはできません。 |
login_hint |
(省略可) | アプリが認証しようとしているユーザーを把握している場合は、このパラメータを認証サーバーにヒントとして提供できます。このヒントを渡すと、アカウント選択ツールが抑制され、ログイン フォームのメールボックスが事前入力されるか、適切なセッションが選択されます(ユーザーがマルチログインを使用している場合)。これにより、アプリが間違ったユーザー アカウントにログインした場合に発生する問題を回避できます。値は、メールアドレスまたは sub 文字列(ユーザーの Google ID と同等)のいずれかです。 |
prompt |
(省略可) | 認可サーバーがユーザーに再認証と同意を求めるかどうかを指定する、スペース区切りの文字列値のリスト。使用できる値は次のとおりです。
値が指定されておらず、ユーザーがアクセスを承認していない場合は、同意画面が表示されます。 |
ID トークンの検証
Google から直接送信されたことを確認できない限り、すべての ID トークンをサーバーで検証する必要があります。たとえば、サーバーはクライアント アプリから受信した ID トークンが真正なものであることを確認する必要があります。
ID トークンをサーバーに送信する一般的な状況は次のとおりです。
- 認証が必要なリクエストとともに ID トークンを送信する。ID トークンには、リクエストを行った特定のユーザーと、その ID トークンが付与されたクライアントが示されます。
ID トークンは機密情報であり、傍受されると不正使用される可能性があります。これらのトークンは、HTTPS 経由でのみ、POST データ経由またはリクエスト ヘッダー内でのみ送信することで、安全に処理されるようにする必要があります。ID トークンをサーバーに保存する場合は、安全に保存する必要があります。
ID トークンが便利な理由の一つは、アプリのさまざまなコンポーネント間で渡すことができる点です。これらのコンポーネントは、アプリとユーザーを認証する軽量な認証メカニズムとして ID トークンを使用できます。ただし、ID トークン内の情報を使用したり、ユーザーが認証したというアサーションとして使用したりするには、その情報を検証する必要があります。
ID トークンの検証には、次の手順が必要です。
- ID トークンが発行元によって適切に署名されていることを確認します。Google が発行したトークンは、ディスカバリ ドキュメントの
jwks_uri
メタデータ値で指定された URI にある証明書のいずれかを使用して署名されます。 - ID トークンの
iss
クレームの値がhttps://accounts.google.com
またはaccounts.google.com
と等しいことを確認します。 - ID トークンの
aud
クレームの値がアプリのクライアント ID と一致していることを確認します。 - ID トークンの有効期限(
exp
クレーム)が切れていないことを確認します。 - リクエストで 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 標準を使用できます。
OpenID に準拠するには、認証リクエストに
openid profile
スコープ値を含める必要があります。ユーザーのメールアドレスを含めたい場合は、追加のスコープ値
email
を指定できます。profile
とemail
の両方を指定するには、認証リクエスト URI に次のパラメータを含めます。scope=openid%20profile%20email
- アクセス トークンを承認ヘッダーに追加し、ユーザー情報エンドポイントに 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 リクエスト オブジェクトを除く)。