Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase, login by same email different provider

I want my users can login using many different provider but they will get same result if they use only one email address. For example, in stackoverflow I can login by Facebook, Google ... but I still can keep my profile as well as my posts ...

In Firebase Web, for example if my user created an account with email/password provider, his email="[email protected]" password="123456". This account has uid="account1" and I use this uid as a key to store additional information about him in Firebase Database.

Once day, he choose login by Google provider and Facebook provider (still [email protected]), I test with 2 cases in auth setting:

  • "Prevent creation of multiple accounts with the same email address": new Google login will override old "account1" and I can not create new Facebook account with "[email protected]" due to error: "An account already exists with the same email address". Which both I don't want to happend

  • "Allow creation of multiple accounts with the same email address": with this option I can create many account with same email address but they have diffrent uid and I don't know how to link these uid to "account1"? I also can't get email (email = null) after login by Google and Facebook.

So can firebase help me do the thing that I love in many App (login by many different ways but same result)?

like image 403
Duc Hoang Avatar asked Sep 28 '17 01:09

Duc Hoang


2 Answers

This is supported by Firebase Auth through the "Prevent creation of multiple accounts with the same email address" setting. However, Google is a special case as it is a verified provider and will overwrite unverified accounts with the same email. For example, if an email/password account is created and not verified and then a user signs in with Google with the same email, the old password is overridden and unlinked but the same user (same uid) is returned.

For other cases, this is how it is handled.

Let's say you sign in with Email/Password using an email/password with account [email protected]. A user then tries to sign in with a Facebook provider using the same email. The Auth backend will throw an error and linking will be required. After that is done, a user can sign in with either accounts.

Here is an example:

    var existingEmail = null;
    var pendingCred = null;
    var facebookProvider = new firebase.auth.FacebookAuthProvider();
    firebase.auth().signInWithPopup(facebookProvider)
      .then(function(result) {
        // Successful sign-in.
      });
      .catch(function(error) {
        // Account exists with different credential. To recover both accounts
        // have to be linked but the user must prove ownership of the original
        // account.
        if (error.code == 'auth/account-exists-with-different-credential') {
          existingEmail = error.email;
          pendingCred = error.credential;
          // Lookup existing account’s provider ID.
          return firebase.auth().fetchProvidersForEmail(error.email)
            .then(function(providers) {
               if (providers.indexOf(firebase.auth.EmailAuthProvider.PROVIDER_ID) != -1) {
                 // Password account already exists with the same email.
                 // Ask user to provide password associated with that account.
                 var password = window.prompt('Please provide the password for ' + existingEmail);
                 return firebase.auth().signInWithEmailAndPassword(existingEmail, password);    
               } else if (providers.indexOf(firebase.auth.GoogleAuthProvider.PROVIDER_ID) != -1) {
                 var googProvider = new firebase.auth.GoogleAuthProvider();
                 // Sign in user to Google with same account.
                 provider.setCustomParameters({'login_hint': existingEmail});
                 return firebase.auth().signInWithPopup(googProvider).then(function(result) {
                   return result.user;
                 });
               } else {
                 ...
               }
            })
            .then(function(user) {
              // Existing email/password or Google user signed in.
              // Link Facebook OAuth credential to existing account.
              return user.linkWithCredential(pendingCred);
            });
        }
        throw error;
      });

like image 57
bojeil Avatar answered Oct 21 '22 03:10

bojeil


The above code by @bojeil is correct Except it misses out one line.

var existingEmail = null;
var pendingCred = null;
**var facebookprovider = new firebase.auth.FacebookAuthProvider();**
firebase.auth().signInWithPopup(facebookProvider)

you have to initialize facebookprovider before passing it as an argument.

like image 35
Aarav Kumar Avatar answered Oct 21 '22 02:10

Aarav Kumar