Have you migrated or want to migrate to the SignIn with Google that uses CredentialsManager and it’s not workin? Well, in my experience, when I tried recently to integrate this in a new project I faced 2 major issues that consumed some of my time.
First Issue
The first one was the lack of some specifications from android developers site: https://developer.android.com/identity/sign-in/credential-manager-siwg. Here they tell us to integrate this code
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(WEB_CLIENT_ID)
.setAutoSelectEnabled(true)
// nonce string to use when generating a Google ID token
.setNonce(nonce)
.build()
when we want to instantiate a signin request, but apparently by doing only that is not working. Nothing happens. The problem is that works only if you already have saved the credentials in the CredentialManager, but at a first install of the app that is not the case so what I had to do was to catch the exception and retry with another object, GetSignInWithGoogleOption, that triggers all the accounts dialog to show. Below is the working implementation for SignIn with Google that retrieves credentials from Credential Manager, the fix for the issue is inside NoCredentialException
@Singleton
class AuthRepository @Inject constructor(
private val credentialManager: CredentialManager,
private val resourceProvider: ResourceProvider,
private val firebaseAuth: FirebaseAuth
) : IAuthRepository {
override suspend fun signInWithGoogle(context: Context): Result<Unit> {
return try {
// Step 1: Try to get credential using Credential Manager
val googleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true) // First, try existing accounts
.setServerClientId(resourceProvider.getString(R.string.default_web_client_id))
.setAutoSelectEnabled(true)
.build()
val credentialResponse = getCredentials(googleIdOption, context)
handleSignInWithCredentials(credentialResponse)
Log.d(TAG, "Firebase sign-in successful: ${firebaseAuth.currentUser?.email}")
Result.success(Unit)
} catch (e: NoCredentialException) {
Log.e(TAG, "No authorized accounts found, trying all accounts")
val googleIdOptionAll = GetSignInWithGoogleOption.Builder(
serverClientId = resourceProvider.getString(R.string.default_web_client_id)
)
.build()
val credentialResponse = getCredentials(googleIdOptionAll, context)
handleSignInWithCredentials(credentialResponse)
Result.failure(e)
} catch (e: GetCredentialException) {
Log.e(TAG, "Credential error: ${e.message}", e)
Result.failure(e)
} catch (e: GoogleIdTokenParsingException) {
Log.e(TAG, "Invalid Google ID token: ${e.message}", e)
Result.failure(e)
} catch (e: Exception) {
Log.e(TAG, "Sign-in error: ${e.message}", e)
Result.failure(e)
}
}
private suspend fun handleSignInWithCredentials(credentialResponse: GetCredentialResponse) {
// Step 2: Extract the ID token from the credential
val idToken = handleSignIn(credentialResponse)
// Step 3: Authenticate with Firebase using the ID token
val credential = GoogleAuthProvider.getCredential(idToken, null)
firebaseAuth.signInWithCredential(credential).await()
}
/**
* Retrieves credentials from Credential Manager.
*
*/
private suspend fun getCredentials(
googleIdOption: CredentialOption,
context: Context
): GetCredentialResponse {
val request = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
val result = credentialManager.getCredential(
context = context,
request = request
)
return result
}
private fun handleSignIn(result: GetCredentialResponse): String {
val credential = result.credential
if (credential is CustomCredential && credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
return googleIdTokenCredential.idToken
} catch (e: GoogleIdTokenParsingException) {
Log.e(TAG, "Received an invalid Google ID token response", e)
throw e
}
} else {
Log.e(TAG, "Unexpected credential type: ${credential.type}")
throw IllegalStateException("Unexpected type of credential")
}
}
override suspend fun signOut(): Result<Unit> {
return try {
firebaseAuth.signOut()
Log.d(TAG, "User signed out successfully")
Result.success(Unit)
} catch (e: Exception) {
Log.e(TAG, "Sign-out error: ${e.message}", e)
Result.failure(e)
}
}
override fun isUserSignedIn(): Boolean {
return firebaseAuth.currentUser != null
}
companion object {
private const val TAG = "AuthRepository"
}
}
Second Issue
In order to make the SignIn with Google work, I had to do first the setup for Google Cloud Console project as the official documentation states and also a Firebase setup which to be honest was not very obvious to me from the beginning that I had to do (it is mentioned briefly on the android developer documentation but somehow I missed it).
So I did the setup on these 2 places, downloaded from Firebase the google-services.json file like this:
- Go to Project Overview and click on the settings icon and then select Project settings option

2. Scroll down the page until you see the Android apps section.

So, the second issue was because of the release build variant. In my project I have 2 variants: debug and release. So I needed to create 2 separate projects in Firebase, one for testing and one for prod. The debug worked OK when I ran the project locally on my phone using the debug variant, but the release variant kept thwrowing an error when running locally on my device:
Account reauth failed.
I kept investigating and the only issue seemed to be with the SHA-1 and SHA-256 fingerprints but didn’t understand why as they were the same as the ones from Play Store which by the way can be found in:
Google Play Console -> your app -> Test and release -> App Integrity -> Play app signing
-> Settings

So I checked the fingerprints from the first section App signing key certificate and they were the same as the ones from Firebase, but somehow somethings was wrong.

And it was, because when we run locally Google doesn’t get to sign the app as it would when we upload it to the store so the fingerprint that was used was not good as I was running the app locally even though it was in the release variant, so in order to have the proper key when running a
releasevariant, we also have to add from Play Store to Firebase the Upload key certificate fingerprints which can be found down on the App Signing page from Play Store.

Long story short, in Firebase project settings if we have a release variant that we want to run it both on store and locally we will need to have 2 SHA-1 and 2 SHA-256 fingerprints. After you do the modifications re-download the google-services.json file and add it into your project for the release variant. This is how I have them in the project:

And in build.gradle.kts
buildTypes {
getByName("release") {
isMinifyEnabled = true
isShrinkResources = true
isDebuggable = false
signingConfig = signingConfigs.getByName("release")
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
getByName("debug") {
isMinifyEnabled = false
isShrinkResources = false
isDebuggable = true
applicationIdSuffix = ".debug"
}
}
I hope my pain eased a bit some of your pain :) If you found this post helpful you can thank me by buying me a coffee :)
