最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Handling linking accounts in Firebase - Stack Overflow

programmeradmin2浏览0评论

I am following Firebase's instruction on social login. Below is an example of what I am using and it is all working fine from a login authentication perspective.

I have, however, both Google and Facebook login working independently.

What I would like now to be able to do is link the accounts. You can see below in fact where this might go (see the comment):

If you are using multiple auth providers on your app you should handle linking the user's accounts here.

I have tried many variations of what I think should go here, but to no avail. Can anyone guide me in relation to what they think should go here? Thanks!

function initFBApp() {
    // Result from Redirect auth flow.
    // [START getidptoken]
    firebase.auth().getRedirectResult().then(function (result) {
        if (result.credential) {
            // This gives you a Facebook Access Token. You can use it to access the Facebook API.
            var token = result.credential.accessToken;
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-oauthtoken').textContent = token;
        }
        else {
            document.getElementById('FBquickstart-oauthtoken').textContent = 'null';
            // [END_EXCLUDE]
        }
        // The signed-in user info.
        var user = result.user;
    }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
        // [START_EXCLUDE]
        if (errorCode === 'auth/account-exists-with-different-credential') {
            alert('You have already signed up with a different auth provider for that emails.');
            // If you are using multiple auth providers on your app you should handle linking
            // the user's accounts here.
        }
        else {
            console.error(error);
        }
        // [END_EXCLUDE]
    });
    // [END getidptoken]
    // Listening for auth state changes.
    // [START authstatelistener]
    firebase.auth().onAuthStateChanged(function (user) {
        if (user) {
            // User is signed in.
            var displayName = user.displayName;
            var email = user.email;
            var emailVerified = user.emailVerified;
            var photoURL = user.photoURL;
            var isAnonymous = user.isAnonymous;
            var uid = user.uid;
            var providerData = user.providerData;
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-sign-in-status').textContent = 'Signed in';
            document.getElementById('FBquickstart-sign-in').textContent = 'Log out';
            document.getElementById('FBquickstart-account-details').textContent = JSON.stringify(user, null, '  ');
            // [END_EXCLUDE]
        }
        else {
            // User is signed out.
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-sign-in-status').textContent = 'Signed out';
            document.getElementById('FBquickstart-sign-in').textContent = 'Log in with Facebook';
            document.getElementById('FBquickstart-account-details').textContent = 'null';
            document.getElementById('FBquickstart-oauthtoken').textContent = 'null';
            // [END_EXCLUDE]
        }
        // [START_EXCLUDE]
        document.getElementById('FBquickstart-sign-in').disabled = false;
        // [END_EXCLUDE]
    });
    // [END authstatelistener]
    document.getElementById('FBquickstart-sign-in').addEventListener('click', toggleFBSignIn, false);
}

I am following Firebase's instruction on social login. Below is an example of what I am using and it is all working fine from a login authentication perspective.

I have, however, both Google and Facebook login working independently.

What I would like now to be able to do is link the accounts. You can see below in fact where this might go (see the comment):

If you are using multiple auth providers on your app you should handle linking the user's accounts here.

I have tried many variations of what I think should go here, but to no avail. Can anyone guide me in relation to what they think should go here? Thanks!

function initFBApp() {
    // Result from Redirect auth flow.
    // [START getidptoken]
    firebase.auth().getRedirectResult().then(function (result) {
        if (result.credential) {
            // This gives you a Facebook Access Token. You can use it to access the Facebook API.
            var token = result.credential.accessToken;
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-oauthtoken').textContent = token;
        }
        else {
            document.getElementById('FBquickstart-oauthtoken').textContent = 'null';
            // [END_EXCLUDE]
        }
        // The signed-in user info.
        var user = result.user;
    }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
        // [START_EXCLUDE]
        if (errorCode === 'auth/account-exists-with-different-credential') {
            alert('You have already signed up with a different auth provider for that emails.');
            // If you are using multiple auth providers on your app you should handle linking
            // the user's accounts here.
        }
        else {
            console.error(error);
        }
        // [END_EXCLUDE]
    });
    // [END getidptoken]
    // Listening for auth state changes.
    // [START authstatelistener]
    firebase.auth().onAuthStateChanged(function (user) {
        if (user) {
            // User is signed in.
            var displayName = user.displayName;
            var email = user.email;
            var emailVerified = user.emailVerified;
            var photoURL = user.photoURL;
            var isAnonymous = user.isAnonymous;
            var uid = user.uid;
            var providerData = user.providerData;
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-sign-in-status').textContent = 'Signed in';
            document.getElementById('FBquickstart-sign-in').textContent = 'Log out';
            document.getElementById('FBquickstart-account-details').textContent = JSON.stringify(user, null, '  ');
            // [END_EXCLUDE]
        }
        else {
            // User is signed out.
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-sign-in-status').textContent = 'Signed out';
            document.getElementById('FBquickstart-sign-in').textContent = 'Log in with Facebook';
            document.getElementById('FBquickstart-account-details').textContent = 'null';
            document.getElementById('FBquickstart-oauthtoken').textContent = 'null';
            // [END_EXCLUDE]
        }
        // [START_EXCLUDE]
        document.getElementById('FBquickstart-sign-in').disabled = false;
        // [END_EXCLUDE]
    });
    // [END authstatelistener]
    document.getElementById('FBquickstart-sign-in').addEventListener('click', toggleFBSignIn, false);
}
Share Improve this question edited May 30, 2022 at 21:16 Daniel Widdis 9,13113 gold badges48 silver badges68 bronze badges asked Sep 12, 2016 at 22:09 Alan PowerAlan Power 3411 gold badge3 silver badges13 bronze badges 3
  • Are you manually linking accounts without the firebase auth backend requiring it? or are you doing so because you got the error 'auth/account-exists-with-different-credential'? – bojeil Commented Sep 13, 2016 at 17:47
  • I want to link them so that the user has a single account rather than many. I am successfully getting the error above when authenticating by a 2nd mechanism. I want to now replace the 'auth/account-exists-with-different-credential' message with the linking of the accounts – Alan Power Commented Sep 13, 2016 at 21:10
  • Not sure I understand but if you are getting that error while signing in and as a result are trying to link that account which is returning that error. Check my answer below. – bojeil Commented Sep 16, 2016 at 5:41
Add a comment  | 

4 Answers 4

Reset to default 8

These are roughly the steps on how to handle auth/account-exists-with-different-credential: You will get that error if you are signing in to a new Facebook account that uses the email of another account that already exists. Let's say the existing account is a google account.

You will get that error in getRedirectResult().catch(function(error) {})

The error will also contain an email and credential field. You will need to save the credential (using the recommended sessionStorage). Check this post for more on that: Firebase Authentication Javascript: setCookie for pending Credential for redirect

You then call firebase.auth().fetchProvidersForEmail(error.email) to determine the providers that already exist for that email.

You will then sign in to one of those existing providers and assert that the email is the same as error.email. On success, you will load the pending credential from sessionStorage, re-initialize as described in the other post and link it to the currentUser:

firebase.auth().currentUser.linkWithCredential(savedCred);

You will now have both accounts linked. Keep in mind the existing provider could be a password type. In that case you don't need to save the credential, you just ask the user for the password and sign them in using the same email error.email. You can then call link directly with the error.credential.

BTW, I recommend firebaseui-web which takes care of all this for you: https://github.com/firebase/firebaseui-web

I think the Firebase API changed a bit and firebase.auth().currentUser.link(savedCred); is now firebase.auth().currentUser.linkWithRedirect(provider). In my implementation I'm saving the initially selected provider to sessionStorage and use that with the above method in case account linking is required.

You can also do linkWithPopUp if that suits your needs better.

read example carefully https://firebase.google.com/docs/auth/web/google-signin section "Handling account-exists-with-different-credential Errors"

Redirect mode This error is handled in a similar way in the redirect mode, with the difference that the pending credential has to be cached between page redirects (for example, using session storage).

Below is the relevant snippet of working code (this sits inside an async function). Note that "apples" is just a simplified test record in Firestore representing a shopping cart.

if(error.code === "auth/email-already-in-use"){
    // REMEMBER AUTH CURRENT USER OBJECT
    previousUser = firebase.auth().currentUser;
    // WE MUST HANDLE DB READ AND DELETE WHILE SIGNED IN AS PREVIOUS USER PER FIRESTORE SECURITY RULES
    if(localUserDoc){ //this was saved from .snapshot firing
        if(localUserDoc.data().apples){
            apples = localUserDoc.data().apples;
        }                    
    }
    //DELETE CURRENT USER RECORD WHILE STILL SIGNED IN
    await firebase.firestore().collection("users").doc(previousUser.uid).delete();
    // CLEAN UP DONE. NOW SIGN IN USING EMAIL LINK CREDENTIAL
    try {
        var firebaseUserObj = await firebase.auth().signInAndRetrieveDataWithCredential(credential);
        // FIRESTORE USER RECORD FOR EMAIL LINK USER WAS CREATED WHEN THEY ADDED APPLE TO CART
        try {
            var doc = await firebase.firestore().collection("users").doc(firebaseUserObj.user.uid).get();
            if (doc.exists) {
                if(doc.data().apples){
                    apples = apples + doc.data().apples;
                }
            }
            await firebase.firestore().collection("users").doc(firebaseUserObj.user.uid).update({
                apples: apples
            });
        } catch(error) {
            console.log("Error getting document:", error);
        }
        previousUser.delete();
    } catch (error) {
        console.log(".signInWithCredential err ", error);
    }
}
发布评论

评论列表(0)

  1. 暂无评论