androidgoogle-signingoogle-one-tap

Google sign-in will stop working after signing the app in Play Console


A lot of answers to the topic but the majority are relevant to Firebase and even if I tried with or without Firebase I received the same generic error Exception com.google.android.gms.common.api.ApiException: 10: Developer console is not setup correctly..

The problem:

Using any build (debug, release) and while we have CI-CD to deploy and distribute the app via AppCenter everything works great in all environments (test, production), but, as soon as we release the app in Google Play Console or use the App Bundle Explorer in Play Console to upload the AAB and download the APK to test locally on a device, Google Sign-on doesn't work.

Now while banging my head after 2 weeks of research and trying to understand what that means I did the following.

I have only one Google Cloud Android OAuth Client ID using the upload key SHA1 (I tried adding a second with the Google Play signing SHA1 but didn't really change anything). This is an attempt to fix the issue from this answer https://stackoverflow.com/a/41034093/122769. I actually use the same SHA1 for debug and release. See sign-in report below. Another answer but again relevant to using Firebase (https://stackoverflow.com/a/68094280/122769). I have a sense that I may be doing something wrong around needing to have different SHA1 for the builds; but not sure how to approach it (not sure how/where to add the SHA1 for release https://stackoverflow.com/a/39347133/122769)

./gradlew signingReport:

Variant: testRelease
Config: config
Store: some_path_to_store/release.jks
Alias: company
MD5: 57:MD5
SHA1: 99:SHA1
SHA-256: C3:SHA256
Valid until: Thursday, Month 9, 2045

Variant: prodRelease
Config: config
Store: some_path_to_store/release.jks
Alias: company
MD5: 57:MD5
SHA1: 99:SHA1
SHA-256: C3:SHA256
Valid until: Thursday, Month 9, 2045

The code:

package com.eight.app

import android.content.IntentSender
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.activity.result.ActivityResult
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.Identity
import com.google.android.gms.auth.api.identity.SignInClient
import com.google.android.gms.common.api.ApiException

class MainActivity : AppCompatActivity() {

    private lateinit var errorText: TextView
    private lateinit var googleButton: TextView
    private lateinit var oneTapClient: SignInClient
    private lateinit var signInRequest: BeginSignInRequest
    private val activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult(), ::handleSignInResult)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.a_start)
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
        errorText = findViewById(R.id.errorText)
        googleButton = findViewById(R.id.googleButton)

        oneTapClient = Identity.getSignInClient(this)
        signInRequest = BeginSignInRequest.builder()
            .setPasswordRequestOptions(
                BeginSignInRequest.PasswordRequestOptions.builder()
                    .setSupported(true)
                    .build(),
            )
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.your_web_client_id))
                    // Only show accounts previously used to sign in.
                    .setFilterByAuthorizedAccounts(false)
                    .build(),
            )
            // Automatically sign in when exactly one credential is retrieved.
            .setAutoSelectEnabled(true)
            .build()

        googleButton.setOnClickListener {
            oneTapClient.beginSignIn(signInRequest)
                .addOnSuccessListener(this) { result ->
                    try {
                        val intentSenderRequest = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                        activityResultLauncher.launch(intentSenderRequest)
                    } catch (e: IntentSender.SendIntentException) {
                        Log.e("oneTapSignIn", "Couldn't start One Tap UI: ${e.localizedMessage}")
                        errorText.text = "oneTapSignIn Couldn't start One Tap UI: ${e.localizedMessage}"
                    }
                }
                .addOnFailureListener(this) { e ->
                    // No Google Accounts found. Just continue presenting the signed-out UI.
                    Log.d("oneTapSignIn", e.localizedMessage)
                    errorText.text = "oneTapSignIn addOnFailureListener Couldn't start One Tap UI: ${e.localizedMessage}"
                }
        }
    }

    private fun handleSignInResult(result: ActivityResult) {
        try {
            val credential = oneTapClient.getSignInCredentialFromIntent(result.data)
            val idToken = credential.googleIdToken
            when {
                idToken != null -> {
                    // Got an ID token from Google. Use it to authenticate
                    // with your backend.
                    errorText.text = "Token Success GOt token $idToken"

                    Log.d("onActivityResult", "Got ID token.")
                }

                else -> {
                    // Shouldn't happen.
                    Log.d("onActivityResult", "No ID token!")
                    errorText.text = "No ID token!"
                }
            }
        } catch (e: ApiException) {
            Log.d("onActivityResult", "ApiException No ID token!")
            errorText.text = "Exception $e \n${e.localizedMessage} \n${e.message} \n ${e.cause} \n${e.stackTrace}!"
        }
    }
}

Ideally, I'd like to avoid Firebase, but either way, this is still not working. Is there a way to get more relevant debug information? Any ideas for solutions to test will be appreciated :)


Solution

  • The problem was a 7-year-old forgotten project with some old email account owner in Google Cloud Console created and having the same SHA1 fingerprint OAuth Client ID setup.

    The weirdest thing is though, how two different applications can be created in Google Play Console with the same app signing key! I hope this answer will help others think about non-technical blockers!