androidfirebasekotlinfirebase-authenticationfacebook-authentication

Why do I get null email when I sign in with Apple in Android with firebase?


I keep getting a null email whenever I sign in with Apple. Note that the display name is not null. Also, I've made sure to revoke any tokens before trying to Sign in with Apple again because as per my understanding, Apple only provides the email once, in the initial sign-up. Here is my code for signing in with Apple in Android with Firebase:

The OAuth provider:

fun appleOAuthProvider(appLanguage: String): OAuthProvider {

    return OAuthProvider
        .newBuilder("apple.com")
        .setScopes(listOf("name", "email"))
        .addCustomParameter("locale", currentLanguageLocale(appLanguage))
        .build()

} //: FUN

Signing in:

private fun singInUser(
    auth: FirebaseAuth,
    context: Context,
    appLanguage: String,
    isSigningIn: MutableState<Boolean>,
    completion: (FirebaseUser?) -> Unit
) {

    auth
        .startActivityForSignInWithProvider(context.getActivity(), HelperFunctions.appleOAuthProvider(appLanguage))
        .addOnSuccessListener { authResult ->

            Log.d("SIGN IN WITH APPLE", "activitySignIn:onSuccess:${authResult.user}")
            completion(authResult.user)

        } //: ON SUCCESS

        .addOnFailureListener { e ->

            Log.w("SIGN IN WITH APPLE", "activitySignIn:onFailure", e)
            isSigningIn.value = false
            completion(null)

        } //: ON FAILURE

} //: FUN

After signing in, I collect the user's data with the authResult.user I previously got:

private fun collectDataFromApple(
    user: FirebaseUser?,
    completion: (SignInResult) -> Unit
) {

    val uid = user?.uid
    val email = user?.email
    var firstName = separatedFullName(user?.displayName)?.get(0)
    var lastName = separatedFullName(user?.displayName)?.get(1)

    if (firstName.isNullOrEmpty()) {
        firstName = lastName
    } else if (lastName.isNullOrEmpty()){
        lastName = firstName
    }

    completion(
        SignInResult(
            data =
            UserData(
                personalInformation = UserData.PersonalInformation(
                    userID = uid,
                    email = email,
                    firstName = firstName,
                    lastName = lastName,
                    imageBitmap = null,
                    isNewUser = true,
                    isEmailVerified = mutableStateOf(true),
                    firebaseHasData = false
                ),
                addressInformation = UserData.AddressInformation(),
                contributeStatistics = UserData.ContributeStatistics()
            ),
            errorMessage = null
        )
    )

} //: FUN

The user?.email returns null for an unknown reason. The firstName and lastName are not null, however. Why is that?


Solution

  • When you authenticate your users in Firebase using the Facebook provider, the email address of the user is not present inside the FirebaseUser object. So to solve this, you have to read the list of providers and get the second provider as in the following lines of code:

    val auth = Firebase.auth
    val email = auth.currentUser?.providerData?.get(1)?.email
    

    Do you know why I have to get the second item from the list and not the first one?

    The FirebaseUser#getProviderData() method returns an object of type UserInfo which:

    Represents a collection of standard profile information for a user. Can be used to expose profile information returned by an identity provider, such as Google Sign-In or Facebook Login.

    Typically, the first element (index 0) in the providerData list corresponds to the user's primary authentication provider which is Google, and the second element (index 1) corresponds to the secondary provider, which, in this case, is Apple, in your use-case.

    If you want to have the email present inside the FirebaseUser object as well, then I recommend you update the object using FirebaseUser#updateEmail(email).