Empty email field of Firebase Auth User using Facebook Login Integration (Firebase 3.0)

22,267

Solution 1

after reading post in firebase-talk google group here https://groups.google.com/forum/#!topic/firebase-talk/gPGNq-IkTLo, I found out the answer. The issue was happened because I'm using "Allow creation of multiple accounts with the same email address" in Firebase Auth sign-in method.

So I change the option into: "Prevent creation of multiple accounts with the same email address" can it's working properly now. It's simple as that. It's true I need more logic to merge accounts having the same email address, but it's okay.

Maybe everyone else having the same issue, can also try this, and hopefully it's solved as well.

Solution 2

Some Facebook accounts are created using Mobile numbers, so whenever we request for email address we get an empty string.

In the following image, you can see that the facebook account can either set their Primary contact as email address or Mobile number. So, if a person has marked mobile number as primary, then their email address can't be retrieved.

In my case, I had forgot to verify my facebook account, so initially my email address wasn't even showing in Primary contact. So, if your not getting email address, then please go over to General settings and see whether primary account is set to email address or not.

enter image description here

Solution 3

I found the same issue, where email was set to "--" on firebase auth. I was missing permission to read email, which I fixed by:

LoginButton mFacebookSignInButton = (LoginButton) findViewById(R.id.facebook_sign_in_button);
mFacebookSignInButton.setReadPermissions("email", "public_profile");

I hope this helps somebody in future having same issue.

Solution 4

This worked for me.

There is something called providerData in the FirebaseUser. It consists of two data, one from Firebase and another from your sign-in provider (Google, Facebook etc).

FirebaseUser's object

I am able to get the email from the second providerData.

Solution 5

I found the solution. Here is my code

import android.app.ProgressDialog;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;

import com.app.pizzawheel.Common.Globals;
import com.facebook.AccessToken;
import com.facebook.AccessTokenTracker;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.facebook.login.widget.LoginButton;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.AuthCredential;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FacebookAuthProvider;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import android.support.annotation.NonNull;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Arrays;

public class GetStartedActivity extends AppCompatActivity {

    CallbackManager callbackManager;
    AccessTokenTracker accessTokenTracker;
    AccessToken accessToken;
    private FirebaseAuth mAuth;
    ProgressDialog progress;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FacebookSdk.sdkInitialize(this.getApplicationContext());

        setContentView(R.layout.activity_getstarted);
        getSupportActionBar().hide();
        mAuth = FirebaseAuth.getInstance();

        callbackManager = CallbackManager.Factory.create();
        final LoginButton loginButton = (LoginButton) findViewById(R.id.fb_login);
        final ImageButton btnFBLogin = (ImageButton)findViewById(R.id.btn_fb_login);
        loginButton.setReadPermissions("email", "public_profile");

        if (loginButton != null) {
            loginButton.registerCallback(callbackManager,
                    new FacebookCallback<LoginResult>() {
                        @Override
                        public void onSuccess(LoginResult loginResult) {
                            // App code
                            loginButton.setVisibility(View.INVISIBLE);
                            btnFBLogin.setVisibility(View.VISIBLE);
                            accessToken = loginResult.getAccessToken();
                            FBLogin();

                        }

                        @Override
                        public void onCancel() {
                            // App code
                        }

                        @Override
                        public void onError(FacebookException exception) {
                            // App code
                        }
            });
        }
        if(AccessToken.getCurrentAccessToken()!=null) {
            accessToken = AccessToken.getCurrentAccessToken();
            btnFBLogin.setVisibility(View.VISIBLE);
        }
        btnFBLogin.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                FBLogin();
            }
        });

    }

    private void FBLogin(){
        progress = new ProgressDialog(GetStartedActivity.this);
        progress.setMessage("Please Wait...");
        progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progress.setCancelable(false);
        progress.show();

        AuthCredential credential = FacebookAuthProvider.getCredential(accessToken.getToken());
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(GetStartedActivity.this, new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {

                        if (task.isSuccessful()) {
                            GraphRequest request = GraphRequest.newMeRequest(accessToken, new GraphRequest.GraphJSONObjectCallback(){

                                @Override
                                public void onCompleted(JSONObject object, GraphResponse response) {
                                    progress.hide();
                                    progress.dismiss();
                                    try {
                                        Globals.email_address = object.getString("email");
                                        Globals.first_name = object.getString("first_name");
                                        Globals.last_name = object.getString("last_name");
                                    } catch (JSONException e) {
                                        e.printStackTrace();
                                    }

                                    Intent intent = new Intent(GetStartedActivity.this, WelcomeActivity.class);
                                    startActivity(intent);
                                    finish();
                                }
                            });
                            Bundle parameters = new Bundle();
                            parameters.putString("fields","id,email,first_name,last_name");
                            request.setParameters(parameters);
                            request.executeAsync();
                            // Sign in success, update UI with the signed-in user's information

                        } else {
                            progress.hide();
                            progress.dismiss();
                            // If sign in fails, display a message to the user.
//                                    Log.w(TAG, "signInWithCredential:failure", task.getException());
//                                    Toast.makeText(FacebookLoginActivity.this, "Authentication failed.",
//                                            Toast.LENGTH_SHORT).show();
//                                    updateUI(null);
                        }

                    }
                });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        callbackManager.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
Share:
22,267
Admin
Author by

Admin

Updated on August 21, 2021

Comments

  • Admin
    Admin almost 3 years

    I have successfully deployed tutorial code from https://firebase.google.com/docs/auth/android/facebook-login for integrating Firebase Auth logins with Facebook. The users successfully created in Firebase Auth console.

    However, I noticed that the Email field in the user object is empty (—). Strangely, I successfully retrieved the email information directly from provider result objects using GraphRequest using the acquired token.

    Based on the documentation I read (https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser.html#getEmail()), the email field should be populated from login providers.

    Some additional strange behaviour:

    1. After successful login, the onAuthStateChanged is called twice. The value of firebaseAuth.getCurrentUser().getProviderId() is Firebase on both occasion
    2. I try to list down the providers from the FirebaseUser object, user.getProviderData(). I got two providers: firebase and facebook.com
    3. When I tried to update email using FirebaseUser.updateEmail(event.getEmail()), I got this error: An internal error has occurred. [ EMAIL_EXISTS ]

    Is there something I miss or did I do something wrong?

    Here's my code:

    public class LoginActivity extends AppCompatActivity {
        private static final String TAG = "LOGIN_ACTIVITY";
        private static final int RC_SIGN_IN = 777;
        private EventBus eventBus;
        private SweetAlertDialog pDialog;
    
        private FirebaseAuth mAuth;
        private FirebaseAuth.AuthStateListener mAuthListener;
        private CallbackManager mCallbackManager;
        private ImageView mPasswordVisibilityView;
        private TextView txtPassword;
        private boolean justEnteredAuthStateChanged = false;
        private GoogleApiClient mGoogleApiClient;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            FacebookSdk.sdkInitialize(getApplicationContext());
    
            setContentView(R.layout.login);
    
            // Firebase
            mAuth = FirebaseAuth.getInstance();
    
            mAuthListener = new FirebaseAuth.AuthStateListener() {
                @Override
                public void onAuthStateChanged(@NonNull final FirebaseAuth firebaseAuth) {
                    final FirebaseUser user = firebaseAuth.getCurrentUser();
                    if (user != null) {
                        // User is signed in
                        Util.logassert("Auth Provider = " + firebaseAuth.getCurrentUser().getProviderId()); // this is called twice, values of Provider = Firebase 
                        Util.logassert("total provider = " + user.getProviderData().size()); // output = 2. "Firebase" and "facebook.com"
                        for (int i = 0; i < user.getProviderData().size(); i++) {
                            UserInfo info = user.getProviderData().get(i);
                            Util.logassert(info.getProviderId() + ", email = " + info.getEmail()); // both empty
                            Util.logassert("current provider = " + info.getProviderId() + " - " + info);
                        }
    
                    } else {
                        Util.logassert("onAuthStateChanged user logged out");
                    }
                    // ...
    
                }
            };
            mAuth.addAuthStateListener(mAuthListener);
    
            // Firebase Facebook TapAuth
            // Initialize Facebook Login button
    
            mCallbackManager = CallbackManager.Factory.create();
    
            LoginManager.getInstance().registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(LoginResult loginResult) {
                    Util.logassert("facebook:onSuccess:" + loginResult);
                    handleFacebookAccessToken(loginResult.getAccessToken());
                    Util.logassert("granted = " + loginResult.getRecentlyGrantedPermissions()); // output [email and public_profile]
                    Util.logassert("denied = " + loginResult.getRecentlyDeniedPermissions());
                }
    
                @Override
                public void onCancel() {
                    Util.logassert("facebook:onCancel");
                    // ...
                }
    
                @Override
                public void onError(FacebookException error) {
                    Util.logassert("facebook:onError" + error.getMessage());
                    // ...
                }
            });
    
            FancyButton btnFacebook = (FancyButton) findViewById(R.id.btn_facebook_share);
            btnFacebook.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    LoginManager.getInstance().logInWithReadPermissions(LoginActivity.this, Arrays.asList("public_profile", "email"));
                    Util.logassert("try facebook login");
                }
            });
    
    
    
            txtPassword = (EditText) findViewById(R.id.input_password);
        }
    
    
    
        private void handleFacebookAccessToken(AccessToken token) {
            Util.logassert("handleFacebookAccessToken:" + token);
    
            GraphRequest request = GraphRequest.newMeRequest(
                    token,
                    new GraphRequest.GraphJSONObjectCallback() {
                        @Override
                        public void onCompleted(
                                JSONObject object,
                                GraphResponse response) {
                            // Application code
                            Log.v("LoginActivity", response.toString());
                            Util.logassert("graph res = " + response.getRawResponse());
    
                            try {
                                /* successfully output email address from graph request here */
                                FbGraphEvent event = new FbGraphEvent(response.getJSONObject().getString("email"), response.getJSONObject().getString("name"));
                                EventBus.getDefault().postSticky(event);
                            } catch (Exception e) {
                                Log.e("MomInvoice", "Error in parsing json fb graph", e);
                            }
                        }
                    });
            Bundle parameters = new Bundle();
            parameters.putString("fields", "email,name");
            request.setParameters(parameters);
            request.executeAsync();
    
            AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());
    
            mAuth.signInWithCredential(credential)
                    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                        @Override
                        public void onComplete(@NonNull Task<AuthResult> task) {
                            Util.logassert("signInWithCredential:onComplete:" + task.isSuccessful());
    
    
                            if (!task.isSuccessful()) {
                                Util.logassert("signInWithCredential failed coz = " + task.getException().getMessage());
                                Toast.makeText(LoginActivity.this, "Authentication failed :(",
                                        Toast.LENGTH_SHORT).show();
                            }
    
                        }
                    });
        }
    
    
        @Override
        public void onStart() {
            super.onStart();
            Util.logassert("masuk onStart LoginActivity");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
        }
    
        @Override
        protected void onDestroy() {
            if (mAuthListener != null) {
                mAuth.removeAuthStateListener(mAuthListener);
            }
            super.onDestroy();
        }
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
            super.onActivityResult(requestCode, resultCode, data);
    
            if (mCallbackManager != null) {
                mCallbackManager.onActivityResult(requestCode, resultCode, data);
                Util.logassert("hasilx " + requestCode + " = " + resultCode);
            }
    
        }
    }
    
  • Admin
    Admin about 8 years
    Hi @efeturi, unfortunately it's not working for me. I got this error when calling FirebaseUser.updateEmail(): error: An internal error has occurred. [ EMAIL_EXISTS ]
  • efemoney
    efemoney about 8 years
    Firstly, I didn't mean to add an answer. I'm on Stack Exchange Android app and I meant to add a comment. That said, have you checked that the email that you're updating with isn't already among your users? I had a case with Twitter after this where updateEmail wasn't working for a Twitter user. Turns out I used the same email for my Facebook and Twitter.
  • Seiyria
    Seiyria about 8 years
    Thanks for this. I've been struggling with this forever.
  • Ishaan
    Ishaan almost 8 years
    Boy have I been struggling for a long time with this. Thanks, !3 (thumbs up)
  • Jerry Okafor
    Jerry Okafor about 7 years
    In my own case, i discovered that some facebook users registered with just their phone number and the email field is permanently blank and no matter what you do, you will not get an email. @efemoney
  • SagunKho
    SagunKho over 6 years
    I have the same issue, in spite of adding read permissions for "email"
  • furkanbzkurt
    furkanbzkurt about 5 years
    Thank you @Arshak.
  • Abhishek
    Abhishek about 4 years
    .setReadPermissions is now depriciated. Use this instead mFacebookSignInButton.setPermissions("email", "public_profile");
  • Abhishek
    Abhishek about 4 years
    Try this answer. One line code and it's working without any issue.
  • Michale Rezene
    Michale Rezene over 3 years
    What about for Reactjs or Javascript?
  • atlmag
    atlmag over 3 years
    Tihis scenario depends on you code your app to give users option to link accounts. This is what confused me, I thought I needed to "Allow creation of multiple accounts with the same email address" to be able to link accounts, but you don't firebase.google.com/docs/auth/android/account-linking