Firebase Authentication on Android (Kotlin)

March 7, 2019

Why use Firebase Authentication?

  • FirebaseUI Auth for Web, iOS and Android (simple authentication UI provided)
  • Support multiple providers: Google, Facebook, Twitter, Github
  • Support for custom provider
  • Support phone number authentication
  • Support email authentication (and password-less login)
  • Support anonymous user

I am using Firestore and the security rules depends on Firebase Authentication for user authentication.

Setup

Add firebase to Android.

Add firebase dependencies to Module:app build.gradle.

dependencies {
    // https://mvnrepository.com/artifact/com.google.firebase/firebase-auth?repo=google
    implementation "com.google.firebase:firebase-auth:16.1.0"
    // https://mvnrepository.com/artifact/com.firebaseui/firebase-ui-auth
    implementation 'com.firebaseui:firebase-ui-auth:4.3.1'
}

Set up sign-in method at Firebase Console -> Authentication -> Sign-in method.

NOTE: I am using Google, Email and Anonymous authentication only.

com.firebaseui:firebase-ui-auth:4.3.1 require minSdkVersion 15, else will bump into manifest merger failed : uses-sdk:minSdkVersion 15 cannot be smaller than version 16 declared in library [com.firebaseui:firebase-ui-auth:4.3.1] error.

It is possible to bump into java.lang.RuntimeException: Unable to start activity ComponentInfo{*/com.firebase.ui.auth.KickoffActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean error due to incompatibility/bug of appcompat and material library.

The following dependencies are used to resolve the above error.

dependencies {
    // implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
    // implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.appcompat:appcompat:1.1.0-alpha02'

    // implementation 'com.google.android.material:material:1.0.0-beta01'
    // implementation 'com.google.android.material:material:1.0.0'
    implementation 'com.google.android.material:material:1.1.0-alpha03'
}

Activity.

class TestFirebaseAuth : AppCompatActivity(), CoroutineScope {

    companion object {
        private const val REQUEST_SIGN_IN = 1
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_SIGN_IN) {
            val response = IdpResponse.fromResultIntent(data)

            if (resultCode == Activity.RESULT_OK) {
                val user = FirebaseAuth.getInstance().currentUser
                if (user != null) {
                    Timber.d("name=${user.displayName}, email=${user.email}, uid=${user.uid}")
                }
            }
            else {
                // Sign in failed. If response is null the user canceled the
                // sign-in flow using the back button. Otherwise check
                // response.getError().getErrorCode() and handle the error.
                // ...
            }
        }
    }


    fun promptSignin() {
        val providers = arrayListOf(
            AuthUI.IdpConfig.GoogleBuilder().build(),
            AuthUI.IdpConfig.EmailBuilder().build(),
            AuthUI.IdpConfig.AnonymousBuilder().build()
        )

        val intent = AuthUI.getInstance()
            .createSignInIntentBuilder()
            .setAvailableProviders(providers)
            .build()
        startActivityForResult(intent, REQUEST_SIGN_IN)
    }
}

NOTE: As long as FirebaseAuth.getInstance().currentUser is valid, Firestore security rule request.auth shall be populated accordingly as well.

To sign out.

FirebaseAuth.getInstance().signOut()

To listen to (callback) sign in and sign out.

FirebaseAuth.getInstance().addAuthStateListener {
    val currentUser = FirebaseAuth.getInstance().currentUser

    val userText = if (currentUser == null) {
        "No user"
    }
    else {
        if (currentUser.isAnonymous) {
            "Anonymous"
        }
        else {
            currentUser.email ?: "NA"
        }
    }
}

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.