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

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

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

まず、ユーザーがログインしたときに ID トークンを取得します。

  1. Google ログインを構成する場合は、requestIdToken メソッドを呼び出して、サーバーのウェブ クライアント ID を渡します。

    // Request only the user's ID token, which can be used to identify the
    // user securely to your backend. This will contain the user's basic
    // profile (name, profile picture URL, etc) so you should not need to
    // make an additional call to personalize your application.
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.server_client_id))
            .requestEmail()
            .build();
  2. アプリが起動したら、silentSignIn を呼び出して、ユーザーがこのデバイスまたは別のデバイスで Google を使用してアプリにすでにログインしているかどうかを確認します。

    GoogleSignIn.silentSignIn()
        .addOnCompleteListener(
            this,
            new OnCompleteListener<GoogleSignInAccount>() {
              @Override
              public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
                handleSignInResult(task);
              }
            });
  3. ユーザーがサイレント ログインできない場合は、通常のログアウト エクスペリエンスを提示し、ユーザーがログインの選択肢を提供できるようにします。ユーザーがログインしたら、ログイン インテントのアクティビティ結果にあるユーザーの GoogleSignInAccount を取得します。

    // This task is always completed immediately, there is no need to attach an
    // asynchronous listener.
    Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
    handleSignInResult(task);
  4. ユーザーがサイレント モードまたは明示的にログインした後に、GoogleSignInAccount オブジェクトから ID トークンを取得します。

    private void handleSignInResult(@NonNull Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
            String idToken = account.getIdToken();
    
            // TODO(developer): send ID Token to server and validate
    
            updateUI(account);
        } catch (ApiException e) {
            Log.w(TAG, "handleSignInResult:error", e);
            updateUI(null);
        }
    }

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

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("https://yourbackend.example.com/tokensignin");

try {
  List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
  nameValuePairs.add(new BasicNameValuePair("idToken", idToken));
  httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

  HttpResponse response = httpClient.execute(httpPost);
  int statusCode = response.getStatusLine().getStatusCode();
  final String responseBody = EntityUtils.toString(response.getEntity());
  Log.i(TAG, "Signed in as: " + responseBody);
} catch (ClientProtocolException e) {
  Log.e(TAG, "Error sending ID token to backend.", e);
} catch (IOException e) {
  Log.e(TAG, "Error sending ID token to backend.", e);
}

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

HTTPS POST で 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 クレームを確認できます。これは、ホストされている Pod が ユーザーのドメインです。これは、リソースへのアクセスをそのメンバーのみに制限する場合に できます。このクレームがない場合、アカウントは Google がホストするドメイン。

emailemail_verifiedhd フィールドを使用して、 Google はメールアドレスをホストし、その権威があります。Google が信頼できる場合、 そのユーザーが正当なアカウント所有者であることがわかっているため、パスワードやその他の 確認しましょう。

Google が信頼できるケース:

  • email には @gmail.com という接尾辞が付いています。これは Gmail アカウントです。
  • email_verified は true で、hd が設定されています。これは G Suite アカウントです。

ユーザーは Gmail や G Suite を使用せずに Google アカウントを登録できます。日時 email@gmail.com という接尾辞がなく、hd が存在しないと、Google にはありません。 認証には、信頼できる認証方法、パスワード、その他の本人確認方法を使用することが推奨されます。 できます。email_verified も、Google が最初に検証した ユーザーに付与できますが、サードパーティの所有権が付与されます。 アカウントが変更された可能性があります。

これらの検証ステップを実行するために独自のコードを記述するのではなく、 プラットフォームに適した Google API クライアント ライブラリを使用するか、 JWT ライブラリ。開発とデバッグの場合は、tokeninfo を呼び出すことができます。 検証エンドポイントを指定します。

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

Google API クライアント ライブラリのいずれか( JavaNode.jsPHPPython など) は、本番環境で Google ID トークンを検証する場合におすすめの方法です。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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 組織アカウントの場合は、ドメイン名を確認することで hd クレームを確認できます。 Payload.getHostedDomain() メソッドが返す値。ドメインの アカウントがドメインによって管理されていることを確認するには email 申請では不十分です できます。

で確認できます。 <ph type="x-smartling-placeholder">
</ph>
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 the request specified a Google Workspace domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

verifyIdToken 関数は、以下を確認します。 JWT 署名、aud クレーム、exp クレーム、 iss クレーム。

ID トークンが Google Workspace または Cloud 組織アカウントの場合は、hd クレームを確認できます。これは、ホストされている Pod が ユーザーのドメインです。これは、リソースへのアクセスをメンバーのみに制限する場合に使用します 特定のドメインのこの申し立てがない場合は、アカウントが Google がホストするドメインです。

で確認できます。 <ph type="x-smartling-placeholder">
</ph>
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 the request specified a Google Workspace domain
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

verifyIdToken 関数は、以下を確認します。 JWT 署名、aud クレーム、exp クレーム、 iss クレーム。

ID トークンが Google Workspace または Cloud 組織アカウントの場合は、hd クレームを確認できます。これは、ホストされている Pod が ユーザーのドメインです。これは、リソースへのアクセスをメンバーのみに制限する場合に使用します 特定のドメインのこの申し立てがない場合は、アカウントが Google がホストするドメインです。

で確認できます。 <ph type="x-smartling-placeholder">
</ph>
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 the request specified a Google Workspace domain
    # if idinfo['hd'] != DOMAIN_NAME:
    #     raise ValueError('Wrong domain name.')

    # 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 クレームの 3 つが存在します。 hd も確認する必要があります (該当する場合は)そのオブジェクトを調べ、 verify_oauth2_token が返品可能。複数のクライアントが aud クレームも手動で検証します。

tokeninfo エンドポイントの呼び出し

デバッグ用の ID トークンの署名を検証する簡単な方法は次のとおりです。 tokeninfo エンドポイントを使用する。このエンドポイントを呼び出すには、 追加のネットワーク リクエストを作成し、適切なテストを行いながら、検証の大部分を担います。 独自のコードで検証とペイロード抽出を行えます本番環境での使用には適していない リクエストが抑制される可能性があります。また、断続的なエラーが発生することがあります。

tokeninfo エンドポイントを使用して ID トークンを検証するには、HTTPS を使用します。 POST または GET リクエストをエンドポイントに送信し、 id_token パラメータ。 たとえば、トークン「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 アカウントのセキュリティに関する重要な変更を把握して、アカウントを保護するための措置を講じることができます。