androidgoogle-oauthgoogle-signingoogle-one-tapandroid-credential-manager

Credential Manager - How do I create a "SignInWithGoogle" credential?


I'm trying to set up Google's One-Tap but with the new, all-in-one, Credential Manager.

However, after crawling through the (badly written) documentation, I've come to a halt. Upon "Signing in with Google", everything is fine until I get a "NoCredentialException: no credentials available", which makes sense.

But then... how do I create a credential?

Google provides examples to create credentials for both passwords and passkeys but I can't find any information on creating credentials for the "Sign In With Google" button (anywhere on the internet).

"The Sign In With Google Button is supported by Credential Manager with the newest Google ID helper library"

(As stated by Android)

So, I use <CredentialManager>.createCredentialAsync() because that's what Google used during the examples they provided (and explicitly told to do here).

However, Android's createCredentialAsync requires a CreateCredentialRequest and there are only three types that it accepts: "CreatePasswordRequest", "CreatePublicKeyCredentialRequest" and "CreateCustomCredentialRequest".

This is where "Google's ID helper library" mentioned in the quote above is supposed to come in handy. The library has the classes GetGoogleIdOption and GetSignInWithGoogleOption which are both subclasses of GetCustomCredentialOption.

The question now is how am I supposed to get myself a CreateCustomCredentialRequest class (or a subclass of it) for my <CredentialManager>.createCredentialAsync() method.

Google's "newest ID helper library" doesn't provide:

  1. A subclass of CustomCredential & it's Builder for SignInWithGoogle (it does for GoogleIdToken)
  2. A ridiculously long CreateSignInWithGoogleRequest class (or a CreateGoogleIdRequest class) that's a subclass of the CreateCustomCredentialRequest class.

Therefore, since I'm stuck on how I'm supposed to get this CreateCustomCredentialRequest, I'm not sure how I'm supposed to "Integrate Credential Manager with Sign in with Google" either.

Before I end, I want to mention one last thing. In the "Sign up with Google" section, it says:

If no results are returned after setting setFilterByAuthorizedAccounts to true while instantiating the GetGoogleIdOption request and passing it 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.

This doesn't help me because:

  1. This only references GetGoogleIdOption and not GetSignInWithGoogleOption.
  2. There's no explanation on how to "call Sign up with Google".

Afterwards, it says:

Once you instantiate the Google sign-up request, launch the authentication flow similarly as mentioned in the Sign in with Google section.

Is there supposed to be a GetGoogleSignUpRequest class?

Is there anything I'm missing? Did I make a stupid mistake somewhere? Any help on this would be great!

For extra context, I've provided the entirety of my code here: https://www.online-java.com/VjQw6cTKig


Solution

  • Let me try to clarify a few things and try to answer your questions and issues. From the original post, it seems to me that you're trying to sign in your users using Google ID tokens, please correct me if I am wrong. In that case, you don't need to "create" a Google credential. When you try to sign in with a Google account, you rely on the Google accounts that are on the Android device. If there are no Google accounts on the device (or there are, but they need reauthentication, for example if their passwords were changed elsewhere), then the user needs to add a Google account to the device, or reauth the existing accounts first. Now, assuming there are working Google accounts on the device, you can use the Credential Manager APIs (similar to the One Tap APIs) to help users sign-in to your app; the flow is outlined in details here but I will briefly go through them to make it clear.

    After declaring the dependencies (remember that you'd need to include the dependency on the CredentialManager AND the com.google.android.libraries.identity.googleid to be able to use Google ID tokens for your sign-in. Then the flow goes as (make sure you use androidx.* version of classes instead of the ones from the Android framework):

    1. Build a request:

      GetGoogleIdOption googleIdOption = new GetGoogleIdOption.Builder()
         .setFilterByAuthorizedAccounts(true)
         .setServerClientId(WEB_CLIENT_ID)
         .setNonce(NONCE)
         .build();
      GetCredentialRequest request = new GetCredentialRequest.Builder()
        .addCredentialOption(googleIdOption)
        .build();
      
    2. Make the API call:

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

      } );

    3. Retrieve the credentials that the user selected:

      public void handleSignIn(GetCredentialResponse result) {
         Credential credential = result.getCredential();
      
         if (credential instanceof CustomCredential) {
           if (GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(credential.getType())) {
             try {
               GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(((CustomCredential) credential).getData());
             } catch (GoogleIdTokenParsingException e) {
               Log.e(TAG, "Received an invalid google id token response", e);
             }
          }
      

    Now a few important things that may help with your app and also user experience:

    How to use the APIs for "Sign-in with Google" button.

    To do this, you can use the following steps:

    1. You create the same type of request but this time you use GetSignInWithGoogleOption class to build the options, using its Builder.

    2. The rest will be identical to the previous case: you call the same API (using the new options) and you extract the returned credential through the same process.

    There are a few differences worth noting when using the "button" flow: