Firebase Authentication (Google Sign-in) With Android Jetpack Compose

Prerequisite

Add Firebase to Android

Depedencies

dependencies {
    // Import the BoM for the Firebase platform
    implementation platform('com.google.firebase:firebase-bom:29.0.0')

    // Declare the dependency for the Firebase Authentication library
    // When using the BoM, you don't specify versions in Firebase library dependencies
    implementation 'com.google.firebase:firebase-auth-ktx'

    // Also declare the dependency for the Google Play services library and specify its version
    implementation 'com.google.android.gms:play-services-auth:19.2.0'
}

Also, remember setup your app's SHA-1 fingerprint at Firebase Settings.

Enable Google Sign-In at Auth section of Firebase Console.

Code

Activity

class MainActivity : ComponentActivity() {    private val auth: FirebaseAuth = Firebase.auth    private lateinit var googleSignInClient: GoogleSignInClient    private lateinit var authResultLauncher: ActivityResultLauncher<Intent>    private val viewModel: MainViewModel by viewModels()    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        auth.addAuthStateListener { auth ->            Timber.d("addAuthStateListener: ${auth.currentUser}")            viewModel.setCurrentUser(auth.currentUser)        }        // R.string.default_web_client_id is created automatically as per google-services.json,        // though sometimes the IDE might not recognize it        val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)            .requestIdToken(getString(R.string.default_web_client_id))            .requestEmail()            .build()        googleSignInClient = GoogleSignIn.getClient(this, gso)        authResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->            // if (result.resultCode == Activity.RESULT_OK) {            // There are no request codes            val data: Intent? = result.data            val task = GoogleSignIn.getSignedInAccountFromIntent(data)            try {                // Google Sign In was successful, authenticate with Firebase                val account = task.getResult(ApiException::class.java)!!                Timber.d("firebaseAuthWithGoogle:" + account.id)                firebaseAuthWithGoogle(account.idToken!!)            } catch (e: ApiException) {                // Google Sign In failed, update UI appropriately                Timber.w(e, "Google sign in failed")            }            // }        }        setContent {            JourneyTheme {                UserProfileScreen(                    viewModel = viewModel,                    onSignIn = { signIn() },                    onSignOut = { auth.signOut() }                )            }        }            }    fun signIn() {        val signInIntent = googleSignInClient.signInIntent        // startActivityForResult(signInIntent, RC_SIGN_IN)        authResultLauncher.launch(signInIntent)    }    private fun firebaseAuthWithGoogle(idToken: String) {        val credential = GoogleAuthProvider.getCredential(idToken, null)        auth.signInWithCredential(credential)            .addOnCompleteListener(this) { task ->                if (task.isSuccessful) {                    // Sign in success, update UI with the signed-in user's information                    Timber.d("signInWithCredential:success")                    // val user = auth.currentUser                    // updateUI(user)                } else {                    // If sign in fails, display a message to the user.                    Timber.w(task.exception, "signInWithCredential:failure")                    // updateUI(null)                }            }    }    }

Composable

@Composablefun UserProfileScreen(viewModel: MainViewModel, onSignIn: () -> Unit, onSignOut: () -> Unit) {    val currentUser = viewModel.currentUser    Column(modifier = Modifier.padding(16.dp)) {        if (currentUser == null) {            Button(onClick = { onSignIn() }){                Text(text = "Sign in with Google")            }        }        else {            Text(text = "Welcome, ${currentUser.displayName}")            Button(onClick = { onSignOut() } ) {                Text(text = "Sign out")            }        }    }}

ViewModel

class MainViewModel : ViewModel() {    var currentUser by mutableStateOf<FirebaseUser?>(null)        private set    @JvmName("assignCurrentUser")    fun setCurrentUser(user: FirebaseUser?) {        currentUser = user    }}

Potential Errors

Requests to this API firebaseinstallations.googleapis.com method google.firebase.installations.v1.FirebaseInstallationsService.CreateInstallation are blocked.

If you enable restrictions for your API, goto Google Cloud Console -> Credentials, Edit API key -> API restrictions and enable Firebase Installations API.

com.google.firebase.FirebaseException: An internal error has occurred. [ Requests to this API identitytoolkit method google.cloud.identitytoolkit.v1.AuthenticationService.SignInWithIdp are blocked. ]

Enable Identity Toolkit API to your API restrictions.

Requests to this API securetoken.googleapis.com method google.identity.securetoken.v1.SecureToken.GrantToken are blocked.

Enable Token Service API to your API restrictions.

References:

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.