バックエンド サーバーで認証する

バックエンド サーバーと通信するアプリやサイトで Google ログインを使用する場合、そのサーバーで現在ログインしているユーザーを特定しなければならない場合があります。安全にログインできるよう、ユーザーがログインに成功したら、ユーザーの ID トークンを HTTPS を使用してサーバーに送信します。次に、サーバーで ID トークンの整合性を確認し、トークンに含まれるユーザー情報を使用してセッションを確立するか、新しいアカウントを作成します。

ID トークンをサーバーに送信する

ユーザーがログインに成功したら、ユーザーの ID トークンを取得します。

function onSignIn(googleUser) {
  var id_token = googleUser.getAuthResponse().id_token;
  ...
}

次に、HTTPS POST リクエストを使用して ID トークンをサーバーに送信します。

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://yourbackend.example.com/tokensignin');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
  console.log('Signed in as: ' + xhr.responseText);
};
xhr.send('idtoken=' + id_token);

ID トークンの整合性を検証する

HTTPS POST で ID トークンを受信したら、トークンの整合性を確認する必要があります。

如需验证令牌是否有效,请确保满足以下条件:

  • ID 令牌由 Google 正确签名。使用 Google 的公钥(以 JWKPEM 格式提供)来验证令牌的签名。这些密钥会定期轮替;请检查响应中的 Cache-Control 标头,以确定何时应再次检索它们。
  • ID 令牌中 aud 的值等于应用的某个客户端 ID。通过进行这项检查,可以防止向恶意应用颁发的 ID 令牌用于访问应用后端服务器上同一用户的数据。
  • ID 令牌中 iss 的值等于 accounts.google.comhttps://accounts.google.com
  • ID 令牌的过期时间 (exp) 尚未过去。
  • 如果您需要验证该 ID 令牌代表的是 Google Workspace 或 Cloud 组织帐号,则可以检查 hd 声明,该声明指示用户的托管网域。仅允许特定网域的成员访问资源时,必须使用此方法。缺少此声明表示帐号不属于 Google 托管的网域。

我们强烈建议您使用适合您的平台的 Google API 客户端库或通用 JWT 库,而不是自行编写代码来执行这些验证步骤。对于开发和调试,您可以调用我们的 tokeninfo 验证端点。

Google API クライアント ライブラリの使用

本番環境で Google ID トークンを検証するには、いずれかの Google API クライアント ライブラリJavaNode.jsPHPPython など)を使用することをおすすめします。

Java

Java で ID トークンを検証するには、 GoogleIdTokenVerifier オブジェクトを使用します。例:

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

...

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
    // Specify the CLIENT_ID of the app that accesses the backend:
    .setAudience(Collections.singletonList(CLIENT_ID))
    // Or, if multiple clients access the backend:
    //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
    .build();

// (Receive idTokenString by HTTPS POST)

GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
  Payload payload = idToken.getPayload();

  // Print user identifier
  String userId = payload.getSubject();
  System.out.println("User ID: " + userId);

  // Get profile information from payload
  String email = payload.getEmail();
  boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
  String name = (String) payload.get("name");
  String pictureUrl = (String) payload.get("picture");
  String locale = (String) payload.get("locale");
  String familyName = (String) payload.get("family_name");
  String givenName = (String) payload.get("given_name");

  // Use or store profile information
  // ...

} else {
  System.out.println("Invalid ID token.");
}

GoogleIdTokenVerifier.verify() メソッドは、JWT 署名、aud クレーム、iss クレーム、exp クレームを検証します。

ID トークンが Google Workspace または Cloud の組織アカウントを表すことを検証する必要がある場合は、Payload.getHostedDomain() メソッドから返されたドメイン名を確認して hd クレームを検証できます。アカウントをドメインまたは組織によって管理するには、email クレームのドメインだけでは不十分です。

Node.js

Node.js で ID トークンを検証するには、Node.js 用の Google 認証ライブラリを使用します。ライブラリをインストールします。

npm install google-auth-library --save
次に、verifyIdToken() 関数を呼び出します。例:

const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client();
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  // If request specified a G Suite domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

verifyIdToken 関数は、JWT 署名、aud クレーム、exp クレーム、iss クレームを検証します。

ID トークンが Google Workspace または Cloud の組織アカウントを表すことを検証する必要がある場合は、ユーザーのホスト ドメインを示す hd クレームを確認できます。リソースへのアクセスを特定のドメインのメンバーのみに制限する場合は、このオプションを使用する必要があります。このクレームがない場合、アカウントは Google がホストするドメインに属していません。

PHP

PHP で ID トークンを検証するには、PHP 用 Google API クライアント ライブラリを使用します。 Composer を使用するなどしてライブラリをインストールします。

composer require google/apiclient
次に、verifyIdToken() 関数を呼び出します。例:

require_once 'vendor/autoload.php';

// Get $id_token via HTTPS POST.

$client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  // If request specified a G Suite domain:
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

verifyIdToken 関数は、JWT 署名、aud クレーム、exp クレーム、iss クレームを検証します。

ID トークンが Google Workspace または Cloud の組織アカウントを表すことを検証する必要がある場合は、ユーザーのホスト ドメインを示す hd クレームを確認できます。リソースへのアクセスを特定のドメインのメンバーのみに制限する場合は、このオプションを使用する必要があります。このクレームがない場合、アカウントは Google がホストするドメインに属していません。

Python

Python で ID トークンを検証するには、verify_oauth2_token 関数を使用します。例:

from google.oauth2 import id_token
from google.auth.transport import requests

# (Receive token by HTTPS POST)
# ...

try:
    # Specify the CLIENT_ID of the app that accesses the backend:
    idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)

    # Or, if multiple clients access the backend server:
    # idinfo = id_token.verify_oauth2_token(token, requests.Request())
    # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
    #     raise ValueError('Could not verify audience.')

    # If auth request is from a G Suite domain:
    # if idinfo['hd'] != GSUITE_DOMAIN_NAME:
    #     raise ValueError('Wrong hosted domain.')

    # ID token is valid. Get the user's Google Account ID from the decoded token.
    userid = idinfo['sub']
except ValueError:
    # Invalid token
    pass

verify_oauth2_token 関数は、JWT 署名、aud クレーム、exp クレームを検証します。また、verify_oauth2_token が返すオブジェクトを調べて、hd クレームを検証する必要があります(該当する場合)。複数のクライアントがバックエンド サーバーにアクセスする場合は、aud クレームも手動で確認します。

调用 tokeninfo 端点

若要验证用于调试的 ID 令牌签名,一种简单的方法是使用 tokeninfo 端点。调用此端点涉及到一个额外的网络请求,该网络请求会为您执行大部分验证,而您在自己的代码中测试适当的验证和载荷提取时。它不适合在生产代码中使用,因为请求可能会受到限制或出现间歇性错误。

如需使用 tokeninfo 端点验证 ID 令牌,请向该端点发出 HTTPS POST 或 GET 请求,并在 id_token 参数中传递您的 ID 令牌。例如,要验证令牌“XYZ123”,可发出以下 GET 请求:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

如果令牌已正确签名,并且 issexp 声明具有预期值,您会收到 HTTP 200 响应,其正文包含 JSON 格式的 ID 令牌声明。以下是示例响应:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

如果您需要验证此 ID 令牌是否代表 Google Workspace 帐号,可以检查 hd 声明,该声明指示用户的托管网域。仅允许特定网域的成员访问资源时,必须使用此方法。缺少此声明表示帐号不属于 Google Workspace 托管网域。

アカウントまたはセッションを作成する

トークンを検証したら、ユーザーがすでにユーザー データベースに登録されているかどうかを確認します。確立している場合は、ユーザーに対して認証済みセッションを確立します。ユーザーがまだユーザー データベースにない場合は、ID トークン ペイロードの情報から新しいユーザー レコードを作成し、ユーザーのセッションを確立します。アプリで新しく作成されたユーザーを検出したときに、必要な追加のプロフィール情報の入力をユーザーに求めることができます。

クロスアカウント保護機能でユーザー アカウントを保護する

Google を利用してユーザーのログインを行うことで、ユーザーデータを保護するために Google が構築したすべてのセキュリティ機能とインフラストラクチャを利用できます。しかし、万が一ユーザーの Google アカウントが不正使用された場合や、他の重大なセキュリティ イベントが発生した場合、アプリが攻撃を受けやすくなる可能性があります。重大なセキュリティ イベントからアカウントをより適切に保護するには、クロスアカウント保護機能を使用して、Google からセキュリティ通知を受信します。イベントを受信すると、ユーザーの Google アカウントのセキュリティに関する重要な変更を把握して、アカウントを保護するための措置を講じることができます。