Google でログインを実装する

このガイドでは、Google でログインを実装する方法について説明します。次の手順について説明します。

  • アプリに依存関係を追加します。
  • CredentialManager をインスタンス化します。
  • ボトムシート フローを作成します。
  • ボタン フローを作成します。
  • ログイン レスポンスを処理します。
  • エラーを処理します。
  • ログアウトを処理します。

アプリに依存関係を追加する

モジュールの build.gradle ファイルで、認証情報マネージャー、Play 開発者サービス認証googleid の最新バージョンを使用して依存関係を宣言します。

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.6.0-rc02")
    implementation("androidx.credentials:credentials-play-services-auth:1.6.0-rc02")
    implementation("com.google.android.libraries.identity.googleid:googleid:<latest version>")
}

Groovy

dependencies {
    implementation "androidx.credentials:credentials:1.6.0-rc02"
    implementation "androidx.credentials:credentials-play-services-auth:1.6.0-rc02"
    implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"
}

認証情報マネージャーをインスタンス化する

アプリまたはアクティビティのコンテキストを使用して CredentialManager オブジェクトを作成します。

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)

ボトムシートのフローを作成する

ボトムシートは認証情報マネージャーの組み込み UI です。この UI を使用すると、パスワード、パスキー、「Google でログイン」など、すべての認証方法で一貫したユーザー エクスペリエンスが実現します。

以前に承認されたアカウントのログイン リクエストを構成する

GetGoogleIdOption を使用して Google ログイン リクエストを試行し、ユーザーの Google ID トークンを取得します。

次のスニペットは、アカウントが承認済みのアカウントかどうかを確認します。

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
    .setFilterByAuthorizedAccounts(true)
    .setServerClientId(WEB_CLIENT_ID)
    .setAutoSelectEnabled(true)
    .setNonce(generateSecureRandomNonce())
    .build()

リクエストの googleIdOption オブジェクトは次のように構成されています。

  • 以前に承認されたアカウントをフィルタする: 以前にアプリへのログインに使用された承認済みアカウントを取得するには、setFilterByAuthorizedAccountstrue に設定します。

    setFilterByAuthorizedAccounts のデフォルト値は true です。つまり、ボトムシート UI のデフォルトの動作は、以前に承認されたアカウントのみを表示することです。

  • サーバー クライアント ID を設定する: setServerClientId パラメータを設定します。webClientId は、前提条件の完了時に Google Cloud プロジェクトで OAuth 用に設定したウェブ クライアント ID です。

  • 自動ログインを有効にする(省略可): リピーター ユーザーに対して自動ログインを有効にするには、setAutoSelectEnabled(true)setFilterByAuthorizedAccounts(true) を使用します。アプリユーザーが以前にログインしていた場合、不要な摩擦を解消できます。

    自動ログインは、次の条件が満たされている場合にのみ可能です。

    • デバイスに承認済みアカウントが 1 つのみ存在し、その承認済みアカウントが以前にデバイス上のアプリへのログインに使用されたことがある。デバイスに複数の承認済みアカウントがある場合、自動ログインは無効になります。
    • ユーザーが前回のセッションでアプリから明示的にログアウトしていない。
    • ユーザーが Google アカウント設定で自動ログインを無効にしていない。
  • ノンスを設定する(省略可): セキュリティを強化するには、サーバーサイド検証用のノンスを設定します。リプレイ攻撃を防ぐため、setNonce() を使用してサーバーサイドの検証用のノンスを含めることができます。サーバーサイド コードで、リクエストとレスポンスのノンスが同一であることを検証するようにします。

    ノンスを生成するには、次の関数と同様の関数を使用します。この関数は、指定された長さの暗号的に強いランダムなノンスを生成し、Base64 を使用してエンコードします。

fun generateSecureRandomNonce(byteLength: Int = 32): String {
    val randomBytes = ByteArray(byteLength)
    SecureRandom().nextBytes(randomBytes)
    return Base64.encodeToString(randomBytes, Base64.NO_WRAP or Base64.URL_SAFE or Base64.NO_PADDING)
}

ログインをリクエストする

getCredential メソッドを呼び出して、デバイスに承認済みのアカウントがあるかどうかを確認します。

val request: GetCredentialRequest = GetCredentialRequest.Builder()
    .addCredentialOption(googleIdOption)
    .build()

coroutineScope {
    try {
        val result = credentialManager.getCredential(
            request = request,
            context = activityContext,
        )
        handleSignIn(result)
    } catch (e: GetCredentialException) {
        // Handle failures
    }
}

承認済みアカウントがない場合にログイン リクエストを構成する

デバイスにアプリの承認済みユーザーがいない場合、CredentialManagerNoCredentialException を返します。このシナリオでは、ユーザーが別のアカウントを使用して登録できるように、承認済みアカウント フィルタを無効にします。

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
    .setFilterByAuthorizedAccounts(false)
    .setServerClientId(WEB_CLIENT_ID)
    .setNonce(generateSecureRandomNonce())
    .build()

次に、承認済みアカウントの場合と同様にログインをリクエストします。

ボタン フローを作成する

ユーザーが次の条件で「Google でログイン」できるようにする場合は、ボタンを使用します。

  • ユーザーが Credential Manager のボトムシート UI を閉じました。
  • デバイスに Google アカウントがありません。
  • デバイス上の既存のアカウントの再認証が必要です。

ボタンの UI を作成する

これは Jetpack Compose ボタンで行うことができますが、Google でログインのブランド ガイドライン ページで事前承認済みのブランド アイコンを使用することもできます。

ログインフローを作成する

GetSignInWithGoogleOption を使用して Google ログイン リクエストを作成し、Google ID トークンを取得します。

val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(
    serverClientId = WEB_CLIENT_ID
).setNonce(generateSecureRandomNonce())
    .build()

次に、ボトムシート UI の場合と同様に、ログインをリクエストします。

ボトムシートとボタンの共有ログイン関数を作成する

ログインを処理するには、次の手順を実施します。

  1. CredentialManager の getCredential() 関数を使用します。レスポンスが成功した場合は、CustomCredentialGoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL 型)を抽出します。
  2. GoogleIdTokenCredential.createFrom() メソッドを使用して、オブジェクトを GoogleIdTokenCredential に変換します。

  3. 証明書利用者サーバーで認証情報を検証します。

  4. エラーを適切に処理してください。

fun handleSign(result: GetCredentialResponse) {
    // Handle the successfully returned credential.
    val credential = result.credential

    when (credential) {
        is CustomCredential -> {
            if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
                try {
                    // Use googleIdTokenCredential and extract the ID for server-side validation.
                    val googleIdTokenCredential = GoogleIdTokenCredential
                        .createFrom(credential.data)
                } catch (e: GoogleIdTokenParsingException) {
                    Log.e(TAG, "Received an invalid google id token response", e)
                }
            } else {
                // Catch any unrecognized credential type here.
                Log.e(TAG, "Unexpected type of credential")
            }
        }

        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential")
        }
    }
}

エラーを処理する

トラブルシューティングに記載されているエラーを確認して、コードが考えられるすべてのエラー シナリオを処理していることを確認します。

ログアウトを処理する

ユーザーがアプリからログアウトするためのメカニズムを提供することが重要です。たとえば、ユーザーがデバイスに複数の Google アカウントを持っていて、別のアカウントからログインすることにした場合などです。たとえば、設定ページでこの情報を提供できます。

認証情報プロバイダは、アクティブな認証情報セッションを保存し、それを使用して、以降のログイン リクエストのログイン オプションを制限する場合があります。たとえば、他の利用可能な認証情報よりもアクティブな認証情報を優先できます。

ユーザーがアプリからログアウトしたら、API の clearCredentialState() メソッドを呼び出して、すべての認証情報プロバイダから現在のユーザー認証情報の状態を消去します。これにより、指定されたアプリの保存済み認証情報セッションをすべて消去するようすべての認証情報プロバイダに通知し、次回ユーザーがログインする際にすべてのログイン オプションを提供します。