Integrate Credential Manager with Sign in with Google

Credential Manager-enabled bottom sheet showing various identities to select from.
Figure 1. The Sign in with Google bottom sheet dialog appearance after integration with the Credential Manager API.

This document explains how to migrate the Sign in with Google bottom sheet dialog from Google Identity Services (GIS) to the Credentials Manager API using the Google ID helper library.

An app that uses the Credential Manager API is configured to present the end user with a consistent Android user interface that allows the user to select from a list of saved sign-in options, including passkey-enabled accounts. This is the recommended Android API for consolidating different credential types and providers. As of Android 14, users can also leverage 3rd party password managers with the Credential Manager API.

Declare dependencies

In your module's build.gradle file, declare a dependency using the latest version of googleid:

implementation "com.google.android.libraries.identity.googleid:googleid:<latest version>"

Follow the instructions to set up your Google API console project. Replace the guidance on including dependencies with the instructions mentioned above.

Instantiate a Google sign-in request

To begin your implementation, instantiate a Google sign-in request. Use GetGoogleIdOption to retrieve a user's Google ID Token.

Kotlin

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(SERVER_CLIENT_ID)
  .build()

Java

GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(SERVER_CLIENT_ID)
  .build();

You should first call the API with the setFilterByAuthorizedAccounts parameter set to true. If there are no credentials available, then call the API again and set setFilterByAuthorizedAccounts to false.

If you want to sign users in automatically when possible, enable the feature with setAutoSelectEnabled in your GetGoogleIdOption request. Automatic sign in is possible when the following criteria are met:

  • The user has exactly one credential saved for your app. That is, one saved password or one saved Google Account.
  • The user hasn't disabled automatic sign-in in their Google Account settings.

To improve sign-in security and avoid replay attacks, use setNonce to include a nonce in each request. Learn more about generating a nonce.

Kotlin

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(SERVER_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>)
  .build()

Java

GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(true)
  .setServerClientId(SERVER_CLIENT_ID)
  .setNonce(<nonce string to use when generating a Google ID token>);
  .build();

Sign in with Google

The steps to set up a Sign in with Google flow are as follows:

  1. Instantiate the GetCredentialRequest and add the googleIdOption created above to retrieve the credentials.
  2. Pass this request to getCredential() (Kotlin) or getCredentialAsync() (Java) call to retrieve the user's available credentials.
  3. Once the API is successful, extract the CustomCredential which holds the result for GoogleIdTokenCredential data.
  4. The CustomCredential's type should be equal to the value of GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL. Convert the object into a GoogleIdTokenCredential using the GoogleIdTokenCredential.createFrom method.
  5. If the conversion succeeds, extract the GoogleIdTokenCredential's ID, validate it, and authenticate the credential on your server.
  6. If the conversion fails with a GoogleIdTokenParsingException, then you may need to update your Sign in with Google library version.
  7. Catch any unrecognized custom credential types.

Kotlin

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

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

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

  when (credential) {
    is PublicKeyCredential -> {
      // Share responseJson such as a GetCredentialResponse on your server to
      // validate and authenticate
      responseJson = credential.authenticationResponseJson
    }

    is PasswordCredential -> {
      // Send ID and password to your server to validate and authenticate.
      val username = credential.id
      val password = credential.password
    }

    is CustomCredential -> {
      if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
        try {
          // Use googleIdTokenCredential and extract id to validate and
          // authenticate on your server.
          val googleIdTokenCredential = GoogleIdTokenCredential
            .createFrom(credential.data)
        } catch (e: GoogleIdTokenParsingException) {
          Log.e(TAG, "Received an invalid google id token response", e)
        }
      } else {
        // Catch any unrecognized custom credential type here.
        Log.e(TAG, "Unexpected type of credential")
      }
    }

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

Java

GetCredentialRequest request = new GetCredentialRequest.Builder()
  .addGetCredentialOption(googleIdOption)
  .build();

// Launch sign in flow and do getCredential Request to retrieve the credentials
credentialManager.getCredentialAsync(
  requireActivity(),
  request,
  cancellationSignal,
  <executor>,
  new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
    @Override
    public void onResult(GetCredentialResponse result) {
      handleSignIn(result);
    }

    @Override
    public void onError(GetCredentialException e) {
      handleFailure(e);
    }
  }
);

public void handleSignIn(GetCredentialResponse result) {
  // Handle the successfully returned credential.
  Credential credential = result.getCredential();

  if (credential instanceof PublicKeyCredential) {
    String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson();
    // Share responseJson i.e. a GetCredentialResponse on your server to validate and authenticate
  } else if (credential instanceof PasswordCredential) {
    String username = ((PasswordCredential) credential).getId();
    String password = ((PasswordCredential) credential).getPassword();
    // Use id and password to send to your server to validate and authenticate
  } else if (credential instanceof CustomCredential) {
    if (GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(credential.getType())) {
      try {
        // Use googleIdTokenCredential and extract id to validate and
        // authenticate on your server
        GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(((CustomCredential) credential).getData());
      } catch (GoogleIdTokenParsingException e) {
        Log.e(TAG, "Received an invalid Google ID token response", e);
      }
    } else {
      // Catch any unrecognized custom credential type here.
      Log.e(TAG, "Unexpected type of credential");
    }
  } else {
    // Catch any unrecognized credential type here.
    Log.e(TAG, "Unexpected type of credential");
  }
}

Sign in with Google button

The Sign in with Google Button is supported by Credential Manager with the newest Google ID helper library. To trigger the Sign in with Google button flow, use the GetSignInWithGoogleOption instead of GetGoogleIdOption, and handle the returned GoogleIdTokenCredential the same way as before.

Sign up with Google

If no results are returned after setting setFilterByAuthorizedAccounts to true while instantiating GetGoogleIdOption request and passing to GetCredentialsRequest, it indicates that there are no authorized accounts to sign in. At this point, you should set setFilterByAuthorizedAccounts(false) and call Sign up with Google.

Kotlin

val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(false)
  .setServerClientId(SERVER_CLIENT_ID)
  .build()

Java

GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
  .setFilterByAuthorizedAccounts(false)
  .setServerClientId(SERVER_CLIENT_ID)
  .build();

Once you instantiate the Google sign up request , launch the authentication flow in a similar manner as mentioned in the Sign in with Google section.

Handle sign out

When a user signs out of your app, call the API clearCredentialState() method to clear the current user credential state and reset the internal state of sign-in.