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"
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:
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:
GetGoogleIdOption
and not GetSignInWithGoogleOption
.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
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):
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();
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);
}
} );
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:
filterByAuthorizedAccounts
to true
. That means users will see only those accounts that have already been used for your app and have given grants for sharing the usual profileId, email, and such with your app. The reason we insist on making the first call with that setting is the following: if your user has, say, 2 Google accounts on the device and had previously used the first account successfully to sign into your app, in subsequent sessions, you probably want the same user to pick the same Google account to avoid creating a duplicate account by choosing the second account. This can be accomplished by setting that attribute to true: it only shows those accounts that have been used before. If such an account exists and the user selects that, the user basically "signs-in" back to your app (see the next bullet point for "sign-up").filterByAuthorizedAccounts
to false
. This means: "show all the Google accounts on the device to the user". In most cases, it means that this user is a new user for your app, so it amounts to basically "Signing-up" with your app.How to use the APIs for "Sign-in with Google" button.
To do this, you can use the following steps:
You create the same type of request but this time you use GetSignInWithGoogleOption class to build the options, using its Builder.
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: