Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if Firebase Facebook user exists without creating a user starting from anonymous user

In Firebase I need to check if a Facebook user exists without creating the user. Initially the user is anonymous, and they try to login with Facebook. I want this to fail if the Facebook account is not already linked to a user in my system. It won't be linked to the current user because they are anonymous,

If I use Auth.signInAndRetrieveDataWithCredential I expected a "auth/user-not-found" error, but instead the user is simply created. Is this a bug or expected?

let credential = firebase.auth.FacebookAuthProvider.credential(
        event.authResponse.accessToken)
    firebase.auth().signInAndRetrieveDataWithCredential(credential).then( (userCredential) => {
        let user = userCredential.user
        app.debug("DEBUG: Existing user signed in:"+user.uid)
        this.loginSuccess(user)
    }).catch( (err) => {
        app.error("ERROR re-signing in:"+err.code)
        $("#login_status_msg").text(err)
    })

If I use User.reauthenticateAndRetrieveDataWithCredential instead I get the error "auth/user-mismatch" which makes sense because user is currently anonymous. However, I was expecting "auth/user-not-found" may be thrown instead if the credential doesn't exist, but that doesn't happen.

I don't see a way to take my anonymous user, have them login with Facebook and then see if another user is already linked to that Facebook credential without creating the user if it doesn't exist.

If you're wondering why? My scenario is: The system allows anonymous users

  1. A user logs in, then converts to a logged in user by registering with Facebook.
  2. App uninstall
  3. App reinstall
  4. User starts up the app and is initially anonymous.
  5. They try and login with Facebook again. At this point I want to stop them from creating a user if they don't have one already. If they have a user ID already, the code works fine and changes their anonymous account ID to the original user ID which is good.
like image 592
Dan F. Avatar asked Oct 28 '25 07:10

Dan F.


1 Answers

I found a solution! It wasn't too hard to implement, but it does seem hacky.

So we know that when using signInAndRetrieveDataWithCredential(cred) for facebook login, the account is created even if it does not exist yet. To solve this, we need to make sure that we handle the following three things:

  1. Detect if the account is new
  2. Delete the current account that was created by firebase
  3. Throw an error to get out of the current flow and return to wherever you were before.

I just implemented and tested this solution, and it seems to work great:

// ... do your stuff to do fb login, get credential, etc:
const userInfo = await firebase.auth().signInAndRetrieveDataWithCredential(credential)

// userInfo includes a property to check if the account is new:
const isNewUser = _.get(userInfo, 'additionalUserInfo.isNewUser', true)

// FIRST, delete the account we just made.
// SECOND, throw an error (or otherwise escape the current context.
if (isNewUser) {
  firebase.auth().currentUser.delete()
  throw new Error('Couldn\'t find an existing account.')
}

// If the user already exists, just handle normal login
return userInfo.user

The reason I did this was to ensure that users had to go through the "create account flow" in my app. Your case would be really easy to implement as well, something like the following:

let credential = firebase.auth.FacebookAuthProvider.credential(event.authResponse.accessToken)

firebase.auth().signInAndRetrieveDataWithCredential(credential)
  .then(userCredential => {
    const isNewUser = userCredential.additionalUserInfo.isNewUser
    if (isNewUser) {
      firebase.auth().currentUser.delete()
      // The following error will be handled in your catch statement
      throw new Error("Couldn't find an existing account.")
    }
    // Otherwise, handle login normally:
    const user = userCredential.user
    app.debug("DEBUG: Existing user signed in:"+user.uid)
    this.loginSuccess(user)
  }).catch( (err) => {
    app.error("ERROR re-signing in:"+err.code)
    $("#login_status_msg").text(err)
  })
like image 53
Noah Allen Avatar answered Oct 29 '25 22:10

Noah Allen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!