Implement Sign in with Google

This guide describes how to implement Sign in with Google and covers the following steps:

  • Add dependencies to your app.
  • Instantiate CredentialManager.
  • Create the bottom sheet flow.
  • Create the button flow.
  • Handle the sign-in response.
  • Handle errors.
  • Handle sign-out.

Add dependencies to your app

In your module's build.gradle file, declare dependencies using the latest version of Credential Manager, Play Services Auth, and 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>"
}

Instantiate Credential Manager

Use your app or activity context to create a CredentialManager object.

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

Create the bottom sheet flow

The bottom sheet is Credential Manager's inbuilt UI. Using this UI creates a consistent experience across all authentication methods, such as passwords, passkeys, and Sign in with Google.

Configure the sign-in request for previously authorized accounts

Attempt a Google sign-in request with GetGoogleIdOption to retrieve the user's Google ID Token.

The following snippets check if the account is an authorized account.

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

The request googleIdOption object is configured as follows:

  • Filter previously authorized accounts: To retrieve the authorized accounts that have previously been used to sign in to your app, set setFilterByAuthorizedAccounts to true.

    Note that the default value for setFilterByAuthorizedAccounts is true, implying that the default behavior for the bottom sheet UI is to display only previously authorized accounts.

  • Set the server client ID: Set the setServerClientId parameter. The webClientId is the Web Client ID you set up for OAuth in your Google Cloud Project while completing the prerequisites.

  • Enable Automatic Sign-in (optional): To enable Automatic Sign-in for returning users, use setAutoSelectEnabled(true) and setFilterByAuthorizedAccounts(true). For your app users, this removes unnecessary friction if they were already previously signed in.

    Automatic Sign-in is only possible when the following criteria are met:

    • There is only a single authorized account on the device and that authorized account was previously used to sign into the app on the device. Multiple authorized accounts on the device disable automatic sign-in.
    • The user has not explicitly signed out of the app during their previous session.
    • The user hasn't disabled Automatic Sign-in in their Google Account settings.
  • Set a nonce (optional): To enable enhanced security, set a nonce for server-side verification. To prevent replay attacks, you can include a nonce for server-side verification with setNonce(). Ensure that your server-side code validates that the request and response nonces are identical.

    To generate the nonce, use a function similar to the following function that generates a cryptographically strong random nonce of a specified length and encodes it using 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)
}

Request sign-in

Check if the user has an authorized account on the device by calling the getCredential method:

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
    }
}

Configure the sign-in request if no authorized accounts are available

If there are no authorized users for your app on the device, CredentialManager returns a NoCredentialException. In this scenario, disable the authorized accounts filter so that the user can use another account to sign up.

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

Next, request sign-in similarly to how you did for authorized accounts.

Create the button flow

Use a button if you want users to be able to Sign in with Google for the following conditions:

  • The user dismissed the Credential Manager bottom sheet UI.
  • There are no Google Accounts on the device.
  • The existing accounts on the device require reauthentication.

Create the button UI

While this can be done with a Jetpack Compose button, you can use a preapproved brand icon from the Sign in with Google Branding Guidelines page.

Create the sign-in flow

Create a Google sign-in request with GetSignInWithGoogleOption to retrieve a Google ID Token.

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

Next, request sign-in similarly to how you did for the bottom sheet UI.

Create the shared sign in function for the bottom sheet and button

To handle the sign-in, complete the following steps:

  1. Use CredentialManager's getCredential() function. If the response is successful, extract the CustomCredential, which should be of type GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.
  2. Convert the object into a GoogleIdTokenCredential using the GoogleIdTokenCredential.createFrom() method.

  3. Validate the credential on your relying party server.

  4. Make sure that you handle errors appropriately.

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")
        }
    }
}

Handle errors

Review the errors listed in Troubleshooting to ensure your code handles all the possible error scenarios.

Handle sign-out

It is important to provide a mechanism for your users to sign out of your app. For example, a user might have multiple Google Accounts on the device and decide to sign in from a different account. You can provide this in your, for example, settings page.

A credential provider might store an active credential session and use it to limit sign-in options for future sign-in requests. For example, it can prioritize the active credential over any other available credential.

When a user signs out of your app, call the API clearCredentialState() method to clear the current user credential state from all credential providers. This will notify all credential providers that any stored credential session for the given app should be cleared, providing users with full sign-in options the next time.