サーバー側の Google ID トークンを確認する

Google から返された ID トークンは、パラメータ名 credential で HTTP POST メソッド リクエストによってログイン エンドポイントに送信されます。

Python 言語の例を次に示します。これは、ID トークンを検証して使用する通常の手順を示しています。

  1. クロスサイト リクエスト フォージェリ(CSRF)トークンを検証します。ログイン エンドポイントに認証情報を送信すると、Google は double-submit-cookie パターンを使用して CSRF 攻撃を防ぎます。送信前にトークンが生成されます。その後、次のコードサンプルに示すように、トークンが Cookie と POST 本文の両方に挿入されます。

    csrf_token_cookie = self.request.cookies.get('g_csrf_token')
    if not csrf_token_cookie:
        webapp2.abort(400, 'No CSRF token in Cookie.')
    csrf_token_body = self.request.get('g_csrf_token')
    if not csrf_token_body:
        webapp2.abort(400, 'No CSRF token in post body.')
    if csrf_token_cookie != csrf_token_body:
        webapp2.abort(400, 'Failed to verify double submit cookie.')
    
  2. ID トークンを確認します。

    トークンが有効であることを確認するには、次の条件を満たしていることを確認します。

    • ID トークンが Google によって適切に署名されている。Google の公開鍵(JWK または PEM 形式で入手可能)を使用して、トークンの署名を検証します。これらの鍵は定期的にローテーションされます。レスポンスの Cache-Control ヘッダーを調べて、鍵を再度取得する必要があるタイミングを判断します。
    • ID トークン内の aud の値が、アプリのクライアント ID のいずれかと等しい。このチェックは、悪意のあるアプリに対して発行された ID トークンが、アプリのバックエンド サーバー上の同じユーザーのデータにアクセスするために使用されることを防ぐために必要です。
    • ID トークン内の iss の値が accounts.google.com または https://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 クレームも手動で確認します。

  3. トークンの有効性を確認したら、Google ID トークンの情報を使用して、サイトのアカウント ステータスを関連付けることができます。

    • 未登録のユーザー: 必要に応じてユーザーが追加のプロフィール情報を提供できる登録ユーザー インターフェース(UI)を表示できます。また、ユーザーは新しいアカウントを作成し、ログインしているユーザー セッションをサイレントに作成できます。

    • サイトにすでに存在するアカウント: エンドユーザーがパスワードを入力し、以前のアカウントを Google 認証情報にリンクできるウェブページを表示できます。これにより、ユーザーが既存のアカウントにアクセスできることを確認します。

    • 連携ユーザーの復帰: ユーザーはサイレント ログインできます。