GoogleAuthUtil と Plus.API から移行する

以前に GoogleAuthUtil.getToken または Plus.API を使用して Google ログインと統合していた場合は、セキュリティとユーザー エクスペリエンスを向上させるため、最新の Sign-In API に移行する必要があります。

アクセス トークンのアンチパターンから移行する

GoogleAuthUtil.getToken で取得したアクセス トークンを、ID アサーションとしてバックエンド サーバーに送信しないでください。トークンがバックエンドに対して発行されたことを簡単に確認できないため、攻撃者によるアクセス トークンの挿入に対して脆弱になります。

たとえば、Android コードが以下の例のような場合は、アプリを現在のベスト プラクティスに移行する必要があります。

Android コード

この例では、アクセス トークン リクエストで oauth2: とスコープ文字列を GoogleAuthUtil.getToken 呼び出し(oauth2:https://www.googleapis.com/auth/plus.login)の scope パラメータとして使用しています。

GoogleAuthUtil.getToken で取得したアクセス トークンで認証するのではなく、ID トークン フローまたは認証コードフローのいずれかを使用します。

ID トークン フローに移行する

必要なのはユーザーの ID、メールアドレス、名前、プロフィール写真の URL のみの場合は、ID トークンのフローを使用します。

ID トークン フローに移行するには、次の変更を行います。

Android クライアントサイド

  • リクエストに応じて GET_ACCOUNTS(連絡先)権限を削除する
  • GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() を使用するコードを、GoogleSignInOptions.Builder.requestIdToken(...) 構成で Auth.GOOGLE_SIGN_IN_API に切り替えます。

サーバーサイド

  • ID トークン認証用の新しいエンドポイントを作成する
  • クライアント アプリの移行後に古いエンドポイントをオフにする

サーバー認証コード フローに移行する

サーバーが Google ドライブ、YouTube、コンタクトなどの他の Google API にアクセスする必要がある場合は、サーバー認証コードフローを使用します。

サーバー認証コードフローに移行するには、次の変更を行います。

Android クライアントサイド

  • リクエストに応じて GET_ACCOUNTS(連絡先)権限を削除する
  • GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() を使用するコードを、GoogleSignInOptions.Builder.requestServerAuthCode(...) 構成で Auth.GOOGLE_SIGN_IN_API に切り替えます。

サーバーサイド

古いエンドポイントと新しいエンドポイントの間で API アクセス ロジックを共有することは引き続き可能です。次に例を示します。

GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(...);
String accessToken = tokenResponse.getAccessToken();
String refreshToken = tokenResponse.getRefreshToken();
Long expiresInSeconds = tokenResponse.getExpiresInSeconds();

// Shared by your old and new implementation, old endpoint can pass null for refreshToken
private void driveAccess(String refreshToken, String accessToken, Long expiresInSeconds) {
   GoogleCredential credential = new GoogleCredential.Builder()
           .setTransPort(...)
           ...
           .build();
   credential.setAccessToken(accessToken);
   credential.setExpiresInSeconds(expiresInSeconds);
   credential.setRefreshToken(refreshToken);
}

GoogleAuthUtil ID トークン フローを移行する

GoogleAuthUtil を使用して ID トークンを取得している場合は、新しい Sign-In API のID トークン フローに移行する必要があります。

たとえば、Android コードが次の例のようになる場合は、移行する必要があります。

Android コード

この例では、ID トークン リクエストで、audience:server:client_id とウェブサーバーのクライアント ID を GoogleAuthUtil.getToken 呼び出しの「スコープ」パラメータとして使用しています(audience:server:client_id:9414861317621.apps.googleusercontent.com)。

新しい Sign-In API ID トークンのフローには、次のようなメリットがあります。

  • 合理化されたワンタップ ログイン エクスペリエンス
  • サーバーは追加のネットワーク呼び出しなしでユーザー プロファイル情報を取得できます

ID トークン フローに移行するには、次の変更を行います。

Android クライアントサイド

  • リクエストに応じて GET_ACCOUNTS(連絡先)権限を削除する
  • GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() を使用するコードを、GoogleSignInOptions.Builder.requestIdToken(...) 構成で Auth.GOOGLE_SIGN_IN_API に切り替えます。

サーバーサイド

新しい Sign-In API は、非推奨の形式を使用する GoogleAuthUtil.getToken とは異なり、OpenID Connect 仕様に準拠した ID トークンを発行します。特に、カード発行会社は https://accounts.google.com になり、スキーマは https になりました。

移行プロセス中、サーバーは古い Android クライアントと新しい Android クライアントの両方から ID トークンを検証する必要があります。トークンの両方の形式を確認するには、使用するクライアント ライブラリに対応する変更を加えます(どちらかを使用している場合)。

  • Java(Google API クライアント ライブラリ): 1.21.0 以降にアップグレード
  • PHP(Google API クライアント ライブラリ): v1 を使用している場合は 1.1.6 以降にアップグレードします。v2 を使用している場合は 2.0.0-RC1 以降にアップグレードします。
  • Node.js: 0.9.7 以降にアップグレード
  • Python または独自の実装: https://accounts.google.comaccounts.google.com の両方の発行元を受け入れます。

GoogleAuthUtil サーバー認証コードフローから移行する

GoogleAuthUtil を使用してサーバー認証コードを取得する場合は、新しい Sign-In API の認証コードフローに移行する必要があります。

たとえば、Android コードが次の例のようになる場合は、移行する必要があります。

Android コード

この例では、サーバー認証コード リクエストで、GoogleAuthUtil.getToken 呼び出し(oauth2:server:client_id:9414861317621.apps.googleusercontent.com)の scope パラメータとして oauth2:server:client_id とウェブサーバーのクライアント ID を使用しています。

新しい Sign-In API 認可コードフローには、次のメリットがあります。

  • 合理化された 1 タップ サインイン エクスペリエンス
  • 以下の移行ガイドに沿って操作すると、認証コードの交換時に、ユーザーのプロフィール情報を含む ID トークンをサーバーが取得できます。

新しい認証コードフローへの移行には、次の変更を行います。

Android クライアントサイド

  • リクエストに応じて GET_ACCOUNTS(連絡先)権限を削除する
  • GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() を使用するコードを、GoogleSignInOptions.Builder.requestServerAuthCode(...) 構成で Auth.GOOGLE_SIGN_IN_API に切り替えます。

サーバーサイド

現在のコードをそのまま使用しますが、GoogleAuthorizationCodeTokenRequest オブジェクトの作成時にトークン サーバー エンドポイントとして https://oauth2.googleapis.com/token を指定します。これにより、別のネットワーク呼び出しを行うことなく、ユーザーのメールアドレス、ユーザー ID、プロファイル情報を含む ID トークンを取得できます。このエンドポイントは完全に下位互換性があり、以下のコードは、古い Android クライアント実装と新しい Android クライアント実装の両方から取得されたサーバー認証コードで機能します。

GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(
                transport,
                jsonFactory,
                // Use below for tokenServerEncodedUrl parameter
                "https://oauth2.googleapis.com/token",
                clientSecrets.getDetails().getClientId(),
                clientSecrets.getDetails().getClientSecret(),
                authCode,
                REDIRECT_URI)
               .execute();

...

// You can also get an ID token from auth code exchange.
GoogleIdToken googleIdToken = tokenResponse.parseIdToken();
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
        .setAudience(Arrays.asList(SERVER_CLIENT_ID))
        .setIssuer("https://accounts.google.com")
        .build();
// Refer to ID token documentation to see how to get data from idToken object.
GoogleIdToken idToken = verifier.verify(idTokenString);
...