I am implementing Google Sign In with Firebase Authentication through the use of Credential Manager.
Below is my implementation:
suspend fun signIn(): AuthResult? {
val credentialManager = CredentialManager.create(context)
val googleIdOption = GetGoogleIdOption.Builder()
.setServerClientId(context.getString(R.string.server_client_id))
.setFilterByAuthorizedAccounts(false)
.setAutoSelectEnabled(true)
.build()
val request = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
val result = try {
val result = credentialManager.getCredential(context, request)
val credential = result.credential
val googleIdTokenCredential = GoogleIdTokenCredential
.createFrom(credential.data)
val googleIdToken = googleIdTokenCredential.idToken
val firebaseCredential =
GoogleAuthProvider.getCredential(googleIdToken, null)
auth.signInWithCredential(firebaseCredential).await()
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
if (e is CancellationException) throw e
null
}
return result
}
The issue
The sign in flow works correctly for normal Google accounts, however when attempting to sign in using a child’s account on their device managed by a parent using Family Link, I receive the following error:
androidx.credentials.exceptions.NoCredentialException: No credentials available
at androidx.credentials.CredentialProviderFrameworkImpl.convertToJetpackGetException$credentials_release(CredentialProviderFrameworkImpl.kt:276)
at androidx.credentials.CredentialProviderFrameworkImpl$onGetCredential$outcome$2.onError(CredentialProviderFrameworkImpl.kt:152)
at androidx.credentials.CredentialProviderFrameworkImpl$onGetCredential$outcome$2.onError(CredentialProviderFrameworkImpl.kt:143)
at android.credentials.CredentialManager$GetCredentialTransport.lambda$onError$2(CredentialManager.java:694)
at android.credentials.CredentialManager$GetCredentialTransport.$r8$lambda$nlbYav9mLBoE6Yh1vFKCvITF3ks(Unknown Source:0)
at android.credentials.CredentialManager$GetCredentialTransport$$ExternalSyntheticLambda2.run(Unknown Source:6)
at androidx.credentials.CredentialManager$$ExternalSyntheticLambda0.execute(D8$$SyntheticClass:0)
at android.credentials.CredentialManager$GetCredentialTransport.onError(CredentialManager.java:693)
at android.credentials.IGetCredentialCallback$Stub.onTransact(IGetCredentialCallback.java:123)
at android.os.Binder.execTransactInternal(Binder.java:1380)
at android.os.Binder.execTransact(Binder.java:1311)
Current Workaround
When the NoCredentialException
is thrown, I run the reattemptSignInUsingLegacyGoogleSignIn()
function which uses the deprecated GoogleSignIn
to authenticate the user with Google. This works correctly for children’s accounts using Family Link without any crashes occurring.
fun reattemptSignInUsingLegacyGoogleSignIn(): IntentSenderRequest {
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(context.getString(R.string.server_client_id))
.requestEmail()
.build();
val mGoogleSignInClient = GoogleSignIn.getClient(context, gso);
val signInIntent = mGoogleSignInClient.signInIntent
val pendingIntent = PendingIntent.getActivity(
context,
0,
signInIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
return IntentSenderRequest.Builder(pendingIntent).build()
}
suspend fun getSignInResultFromIntent(intent: Intent): AuthResult? {
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
val result = try {
val account = task.getResult(ApiException::class.java)
val credential = GoogleAuthProvider.getCredential(account.idToken, null)
auth.signInWithCredential(credential).await()
} catch (e: ApiException) {
Log.w("Auth", "Google sign in failed", e);
Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show()
null
}
return result
}
Since Credential Manager
is the replacement for the deprecated GoogleSignIn
, the child’s account should be able to sign in using it. Is there anything specific I need to do to enable Credential Manager
sign-in for child accounts managed with Family Link?
There are two flows in the CredentialManager that can allow your users sign in via Google: one uses a bottomsheet UI (Let’s call it the OneTap flow) and the second one shows a dialog (and is specific to Google accounts, let’s call that button-flow since it is commonly attached to tapping on a “Sign in with Google” button). As of right now, neither of those two flows support kids accounts. However, we are working on extending the button-flow API to handle kids accounts and I expect that to land relatively soon. The OneTap flow is different and currently we are not sure if we’d want to support kids accounts in that flow since it is kind of against the premise of “one tap to authenticate”.
Once the new feature lands, we will have parity with the old APIs that is now deprecated. Thank you for your patience.
3