firebase-as3 icon indicating copy to clipboard operation
firebase-as3 copied to clipboard

Facebook login after Google login fails.

Open agentphantom opened this issue 8 years ago • 5 comments

Hello @reyco1 and @sfxworks

I was researching about the issue of using the same email address for Facebook and Google login, it seems it doesn't work for security reasons.

You can see in this thread an explanation about it.

I will quote the relevant part for future readers:

To minimize the login UI clicks without compromising the account security, Firebase Authentication has a concept of 'trusted provider', where the identity provider is also the email service provider. For example, Google is the trusted provider for @gmail.com addresses, Yahoo is the trusted provider for @yahoo.com addresses, and Microsoft for @outlook.com addresses.

In the "One Account per Email address" mode, Firebase Authentication tries to link account based on email address. If a user logins from trusted provider, the user immediately signs into the account since we know the user owns the email address.

If there is an existing account with the same email address but created with non-trusted credentials (e.g. non-trusted provider or password), the previous credentials are removed for security reason. A phisher (who is not the email address owner) might create the initial account - removing the initial credential would prevent the phisher from accessing the account afterwards.

I will also update the examples later today to add a popup explaining the error.

agentphantom avatar Feb 02 '17 18:02 agentphantom

So allowing the user to login from multiple providers would fix this option?

sfxworks avatar Feb 02 '17 18:02 sfxworks

The problem happens only with Facebook -> Google.

The Google login provider will always take precedence over the Facebook one, here's an example:

Let's say my email address for Facebook and Google is the same: [email protected]

  1. If I login with Firebase using my Facebook account it will register with my email address, but it won't be trusted.

  2. If I then login with my Google account, the Facebook data will be overwritten with the Google one and the email address will become trusted.

  3. At this step I can't login anymore with Facebook, I will need to login with Google or it won't work at all (the Facebook login doesn't return the refreshToken anymore).

In this case you will have to tell the user that they can't login with Facebook anymore and they should use Google instead.

agentphantom avatar Feb 02 '17 18:02 agentphantom

Found a hack. Not 100% sure if this is a good idea, but it works. Basically, if you log in with Facebook after you've used Google, Firebase will return errorCodeEmailAlreadyInUse error, so all we have to do is check if the error is of that type and just log the user in with Google.

FIRAuth.auth()?.signIn(with: FIRCredentials, completion: { (user, error) in
  if let errorCode = error?._code,
    let authError = FIRAuthErrorCode(rawValue: errorCode) {
    switch authError {
    case .errorCodeEmailAlreadyInUse:
      GIDSignIn.sharedInstance().signIn()
    default: self.showError(withMessage: "Couldn't sign in with Facebook")
    }
  }
})

rlpavel avatar Mar 23 '17 01:03 rlpavel

Nice find!

Tonight I will give it another shot at this issue and document my results.

agentphantom avatar Mar 23 '17 01:03 agentphantom

I tried the following:

I had already my account with Gmail and logged in with Facebook, the login was successful and this was the response:

{
    "kind": "identitytoolkit#VerifyAssertionResponse",
    "federatedId": "http://facebook.com/1127852910645790",
    "providerId": "facebook.com",
    "localId": "QcGrHghblIg4T2qLWP0RVJL8AQf2",
    "emailVerified": false,
    "email": "[email protected]",
    "oauthAccessToken": "<Medium sized string>",
    "oauthExpireIn": 5183999,
    "firstName": "John",
    "lastName": "Smith",
    "fullName": "John Smith",
    "displayName": "John Smith",
    "idToken": "<Long String>",
    "timeZone": "-6",
    "photoUrl": "https://scontent.xx.fbcdn.net/v/t1.0-1/p100x100/418143_223575787734578_1621690654_n.jpg?oh=25b36d4a93ebcede1245e2944b188130&oe=596B6757",
    "context": "",
    "verifiedProvider": [
        "google.com"
    ],
    "needConfirmation": true,
    "rawUserInfo": "{my Facebook profile information as sent from the Graph API}"
}

The important things to notice are:

  • There's not a refreshToken in the response, which is the key for doing anything with auth in Firebase.
  • emailVerified is set to false. This value is set to true when I log in with Google.
  • needConfirmation parameter which only appears when I try the previous sequence of actions.

My guess is that the Swift API already knows about this and gives you this particular error. In my case I will need to manually detect if the refreshToken exists and if not, redirect the user to the Google Auth.

agentphantom avatar Mar 23 '17 02:03 agentphantom