1

My app uses Firebase authentication with 2 providers: Facebook and Google. To allow users to create both Facebook and Google accounts with the same email, I went to Firebase console and checked an option to allow multiple acoounts for email address.

Now it works, but for Facebook, email is always null. How can I get top level email address (linked to multiple accounts) in case when user decides to login with Facebook. I don't want to link providers into one account, I want to keep "allow multiple accounts for one mail address" turned on.

Any ideas how to get mail address in this case?

[edit]

Initialization for Google and Facebook apis:

 GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                .requestIdToken(getString(R.string.default_web_client_id))
                .requestEmail()
                .build();

        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .enableAutoManage(this, this)
                .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
                .build();

        mAuth = FirebaseAuth.getInstance();

        mAuthListener = firebaseAuth ->
        {
            FirebaseUser user = firebaseAuth.getCurrentUser();
            if (user != null)
            {
                // User is signed in
                Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
                String uuid = user.getUid();
                String mail = user.getEmail();

                currentUserUid = user.getUid();

                //Toast.makeText(LoginActivity.this, "Zalogowano. Email: " + user.getEmail() + " uid: " + user.getUid(),
                //        Toast.LENGTH_SHORT).show();

                if (!logout)
                {
                    List<? extends UserInfo> provider = user.getProviderData();
                    AuthSocial(user, currentLoginType); //if "allow multiple accounts for mail enabled, user.getEmail always returns null for Facebook, how to get correct top level email for "multi account" here?
                }
                else
                {
                    //mAuth.signOut();
                }

            }
            else
            {
                // User is signed out
                Log.d(TAG, "onAuthStateChanged:signed_out");
            }
        };

        // [START initialize_fblogin]
        // Initialize Facebook Login button


        mCallbackManager = CallbackManager.Factory.create();
        LoginButton loginButton = (LoginButton) findViewById(R.id.bt_go_facebook);
        loginButton.setReadPermissions("email", "public_profile");
        loginButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>()
        {


            @Override
            public void onSuccess(LoginResult loginResult)
            {
                Log.d(TAG, "facebook:onSuccess:" + loginResult);
                handleFacebookAccessToken(loginResult.getAccessToken());
                currentLoginType = "facebook";
            }

            @Override
            public void onCancel()
            {
                Log.d(TAG, "facebook:onCancel");
                // [START_EXCLUDE]
                //updateUI(null);
                // [END_EXCLUDE]
            }

            @Override
            public void onError(FacebookException error)
            {
                Log.d(TAG, "facebook:onError", error);
                // [START_EXCLUDE]
                //updateUI(null);
                // [END_EXCLUDE]
            }
        });
        // [END initialize_fblogin]
user1209216
  • 7,404
  • 12
  • 60
  • 123

1 Answers1

3

Because facebook allow users to sign-in only with a phone number there are cases in which users do not update their accounts with their email address. Unfortunately, in those cases you cannot have their emaill addresses at all. To solve this, you can use in stead of email address, the provided phone number or the unique Google/Facebook id.

In order to get the email address from facebook profie, you need to use registerCallback method on the callbackManager object. Here is the code:

CallbackManager callbackManager = CallbackManager.Factory.create();
facebookLoginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
    @Override
    public void onSuccess(LoginResult loginResult) {
        AccessToken accessToken = loginResult.getAccessToken();
        handleFacebookAccessToken(accessToken);

        GraphRequest request = GraphRequest.newMeRequest(accessToken, new GraphRequest.GraphJSONObjectCallback() {
            @Override
            public void onCompleted(JSONObject jsonObject, GraphResponse graphResponse) {
                if(jsonObject != null){
                    Profile profile = Profile.getCurrentProfile();
                    String userEmail = jsonObject.optString("email"); // Facebook userEmail

                } 
            }
        });
        Bundle bundle = new Bundle();
        bundle.putString("fields", "email");
        request.setParameters(bundle);
        request.executeAsync();
    }

    @Override
    public void onCancel() {}

    @Override
    public void onError(FacebookException exception) {}
});

And this the way in which you can check wherever your user loged-in with Google or Facebook.

if (firebaseUser != null) {
    for (UserInfo userInfo : firebaseUser.getProviderData()) {
        if (userInfo.getProviderId().equals("facebook.com")) {
            Toast.makeText(MainActivity.this, "User is signed in with Facebook", Toast.LENGTH_SHORT).show();
        }

        if (userInfo.getProviderId().equals("google.com")) {
            createShoppingList(userModel, listName);
            Toast.makeText(MainActivity.this, "You are signed in Google!", Toast.LENGTH_SHORT).show();
        }
    }
}
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • If I disallow multiple accounts for the same mail address, I'm getting mail from Facebook correctly. – user1209216 Apr 18 '17 at 11:40
  • Yes, if the user has set in his/her account the email address correctly. But there are many cases, in which you do not have the email address. Also, if you saw, by default the `multiple accounts` is disabled because is not a very good practice to allow users to have multiple accounts. – Alex Mamo Apr 18 '17 at 11:48
  • My quesion: I have multiuple accounts enabled. How to get correct mail address in this case? Possible or not? – user1209216 Apr 18 '17 at 12:13
  • Yes, you can. Please update your post wiht some lines of code. – Alex Mamo Apr 18 '17 at 12:20
  • Code attached, basically it's copy-paste from Google's sample – user1209216 Apr 18 '17 at 12:29
  • Updated my answer. – Alex Mamo Apr 18 '17 at 12:39
  • Interesting approach, can we get phone numer (if exists) same way, from jsonObject? This is for the case when there is no email (user has signed up with phone number, without providing email) – user1209216 Apr 18 '17 at 15:22
  • Unfortunately, there is no way to get the phone number of a Facebook user via the Graph API. Even not if the user set it to public. – Alex Mamo Apr 18 '17 at 15:37
  • Possible to pass email got as you described to mAuthListener so I will get one consistent callback containing all user info? As you can see, my app is designed to proceed when Facebook (or Google, it does not matter) login succedes, via Firebase auth callback. I guess graph request as you posted is going to be called indendend and I won't be able to grab email on mAuth callback as it's shown in my code sample. Any idea what could be right way in my case? – user1209216 Apr 18 '17 at 15:54
  • I did not understand entirely your last question but assuming you want to use the email as described above, yes you can use it in that way. You can get the other properties from the `profile` object like this: `String userName = profile.getName();` or `String userId = profile.getId();` and so on. – Alex Mamo Apr 18 '17 at 16:04
  • Sorry, maybe I'm not so good with describing what I mean. As you can see, there is 'AuthSocial' method called after Firebase login finished. In your example, you have used callback inside Facebook login button and you got email from Facebook profile. How to pass this email to my AuthSocial method? – user1209216 Apr 18 '17 at 16:14
  • Should I move GraphRequest to my "onAuthStateChanged" listener, try to get Facebook mail there, then pass 'user' object + email to AuthSocial method? Or there is some better way? – user1209216 Apr 18 '17 at 16:21
  • I think i understand now. Yes, there is a better way. You can use `SharedPreferences`. Create a method to set the email in `SharedPreferences` and another one to get the email from `SharedPreferences`. This will solve for sure the problem. – Alex Mamo Apr 18 '17 at 16:25
  • This is still way complicated... can I be sure that when onAuthStateChanged indicates login finished, I get fresh mail address from GraphRequest? What if GraphRequest callback will return after onAuthStateChanged callback and I will have outdated mail? Also, how to determine if my login was performed via Google (so I should read mail from 'user' object), or via Facebook (so I rather should read mail from SharedPreeferences)? In both cases, mAuth.listener callback will be the same... – user1209216 Apr 18 '17 at 16:33
  • Yes you'll get a get fresh email address from GraphRequest. Using `SharedPreeferences` is the simplest way to archive this. Even your last question was not apart of the initial question, please check my updated answer. If you think that my answer helped you, please consider to accept my answer and give a +1 – Alex Mamo Apr 18 '17 at 16:44
  • Already voted up, I will as soon as I test your solution, I will eventually accept your response. The last thing for consider is what to do when email for Facebook is missing. Isn't there any way to get phone number instead? P.s. why SharedPreeferences and not class field instead? I don't need mail to be persistent, it can be stored in memory – user1209216 Apr 18 '17 at 16:50
  • Please take a look at this [post](http://stackoverflow.com/questions/37008733/getting-phone-number-from-facebook-account-kit). Because the email address is needed in more than one activity, generally speaking, is a good practice to use `SharedPreeferences`. But according to your neeeds and complexity, you can use whatever you think it's more apropiate for you. – Alex Mamo Apr 18 '17 at 17:06
  • Account Kit looks like completly different api, I'm confused again, it seems it has nothing to do with Firebase? But I think we need separate topic for it – user1209216 Apr 18 '17 at 17:17
  • I'm sorry i have you confused you. This was only another approach, to make an idea. Please ignore that post. But as far as i know, there is no way to get the phone number out of a facebook user account. – Alex Mamo Apr 18 '17 at 17:20
  • Don't be sorry, I'm confused with Facebook stuff, not your answers. Regarding to Account Kit, it may work with Firebase, but generally not supported: https://groups.google.com/forum/m/?utm_medium=email&utm_source=footer#!topic/firebase-talk/qrb1gWBKO3M – user1209216 Apr 18 '17 at 17:26
  • Yes, you are right. I also read that post. Hope you'll solve this issue asap. Cheers! – Alex Mamo Apr 18 '17 at 17:31
  • Well, I'm starting to think that Firebase was not a good idea. Maybe I should use google/facebook api without any Firebase hooks – user1209216 Apr 18 '17 at 17:35
  • In my opion, Firebase is the best idea. Consider using `SharedPreeferences` and you'll get your work done ;) – Alex Mamo Apr 18 '17 at 17:36
  • Facebook works like a charm, but now I have the same problem with Google account - mail is always null ... do you have any idea? – user1209216 Apr 19 '17 at 08:22
  • Glad to hear this :) Without seeing some code, i cannot say why. I recomand you post another question (with code), so me and other users can answer it. – Alex Mamo Apr 19 '17 at 08:29
  • I have already found a solution for Google mail. Thanks for help. – user1209216 Apr 19 '17 at 09:22
  • Glad to help! Cheers! – Alex Mamo Apr 19 '17 at 09:32
  • @user1209216 I have the same problem as you did 2 years ago. The second account always has null email, for multiple accounts with same email. The account created first Google/Fb will always return email, the second will not. Did you find a solution? – user1961 May 22 '19 at 21:38
  • No, I didn't. It looks like you must retrieve email from provider (Google, Facebook) directly and in Firebase, allow multiple accounts with the same mail. – user1209216 May 23 '19 at 05:00