简体   繁体   中英

Firebase Auth link provider Google sign in issue?

At the first time, while signup with Gmail and password, firebase saved the credentials correctly. But the next time, I Login with Firebase Google authentication with the same Gmail which i gave while signup, the credentials are overriding in firebase account. After overriding the credentials, we are not able to login using that signup credentials. Can anyone explain how to achieve this?

使用 Gmail 和密码注册

谷歌认证

What happened

In the first screenshot you signed in with the email+password provider of Firebase. While this is a valid sign-in method, it means that anyone could've entered that email address, even if they don't actually have access to the Google account for that gmail address.

There is no security risk here, but the level of trust we can put in the value of email address is low. For this reason the emailVerified property of the account is marked as false and you'll typically want to require that the user verify their email address before allowing them to continue.


In the second screenshot, the user signed in with the same email address, but now with the google.com provider of Firebase. This means that Google now verified already that the user has access to the underlying gmail address of the account. Since the google.com provider is the trusted provider for @gmail.com accounts, the system replaces the previous account.


Also see:

What you can do

You'll typically want to prevent multiple users from signing up with the same email address. For this, you'll want to configure Firebase to only allow a single account per email address in the console, and then use account linking so that the two (email+password and google.com) accounts in your scenario are merged.

Did you verify the email or phone number from the first login attempt? If not, this is by design:

After sign-in completion, any previous unverified mechanism of sign-in will be removed from the user and any existing sessions will be invalidated. For example, if someone previously created an unverified account with the same email and password, the user's password will be removed to prevent the impersonator who claimed ownership and created that unverified account from signing in again with the unverified email and password.

Source

I just ran into this problem and here is a longer and more in depth description. (Things change often, this was true in Nov 2021.)

SHORT VERSION: As @Frank van Puffelen said, this is by design. The issue is that email+password is not a trusted provider usually , so a trusted provider like Google Authentication overwrites that method. It does this silently (I think, didn't check every field in GoogleSignInAuthentication object.)

It does auto-link after a password reset. So, one option is to have the user set their password via a _firebaseAuth.sendPasswordResetEmail(email: email);

Also: I don't recommend turning off One account per email address as some others suggests. See the reason for that at the end.

"Weird" Behavior under default One account per email address

In my app, the following happens.

  1. SignUp via email+password for testUser1234@gmail.com.
  2. creates an account for c_example_account@gmail.com with provider=Email/Password as indicated by the envelope/mail icon in the firebaseAuth dashboard. 初始 FirebaseAuth 仪表板的图片
  3. LogOut and re-signin via Google Sign In for c_example_account@gmail.com
  4. The provider is changed. Old provider is Email/Password icon (envelope). New provider is Google icon. (like the bottom three accounts in the screenshot). Note also that the User UID is the same. So anything anything linked to that User UID is still okay.
  5. Since the Email/Password login method (AKA) provider was removed for c_example_account@gmail.com , the user can't login with that method anymore. IMPORTANTLY : This is done silently without the user getting any notification that the Email/Password login was removed .
  6. Trying to sign on using Email/Password will result in an error Incorrect Password . Note: one might expect it to give an error like "Only Google Sign-In is available", but it doesn't. Contrast this to when the email doesn't exist (like trying garbage@123457.com), which has an error Email is not found...

Now, it gets a little weirder...

  1. Suppose the user uses "Reset Password" like being called like this
  Future<void> resetPassword(String email) async {
    await _firebaseAuth.sendPasswordResetEmail(email: email);
  }
  1. Then, the firebaseAuth console has TWO methods for the same USER UID. See the second and third line in the screenshot. 密码重置后的双重登录方式
  2. Now, both methods are allowed. The difference is that the first time was a createUserWithEmailAndPassword() like
      await _firebaseAuth.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );

...but this time it was created via a "Reset" event

  Future<void> resetPassword(String email) async {
    await _firebaseAuth.sendPasswordResetEmail(email: email);
  }

... that gave a link via email sent by firebaseAuth service . In this case, the email was verified .

  1. Recap: Now both methods work. The two methods being (1) Google authentication and (2) Email/Password. In Google parlance, the accounts have been linked: https://firebase.google.com/docs/auth/android/account-linking . Linking means One User UID , multiple login methods

Why the funky behavior when Email/Password is created in two different methods?

~~I couldn't find this documented in firebaseAuth, maybe because I didn't look hard enough or maybe because it's not a common issue. ~~ This behavior is documented in an issue comment from April 2020 .

I think the reason is because the _firebaseAuth.createUserWithEmailAndPassword version has an unverified email . So, anyone can create an account for anyone else assuming that the email+password combination doesn't exist. For example, I could create an account with username president@whitehouse.gov without actually having access to that email. If the actual president logged in via Google Authentication , then I'd have bogus access to that user's info. Except that the clever google engineers decided that the verified Google Authentication then triggers the deletion of the unverified Email/Password provider/account instance.

In short, the logic might be: verified trumps/overrides unverified. See https://firebase.google.com/docs/auth/users#verified_email_addresses

Again, none of this is documented explicitly for Email/Password. But it is hinted at in the documentation, like if a Facebook Auth account gets over-written by a Google Auth .


Snapshot of the Verified Email details

Copied from: https://firebase.google.com/docs/auth/users#verified_email_addresses

Bolded added by me, for emphasis

In some situations, Firebase will automatically link accounts when a user signs in with different providers using the same email address. This can only happen when specific criteria are met, however. To understand why, consider the following situation: a user signs in using Google with a @gmail.com account and a malicious actor creates an account using the same @gmail.com address, but signing in via Facebook. If these two accounts were automatically linked, the malicious actor would gain access to the user's account.

The following cases describe when we automatically link accounts and when we throw an error requiring user or developer action:

  • User signs in with an untrusted provider, then signs in with another untrusted provider with the same email (for example, Facebook followed by GitHub). This throws an error requiring account linking.
  • User signs in with a trusted provider, then signs in with untrusted provider with the same email (for example, Google followed by Facebook). This throws an error requiring account linking.
  • User signs in with an untrusted provider, then signs in with a trusted provider with the same email (for example, Facebook followed by Google). The trusted provider overwrites the untrusted provider . If the user attempts to sign in again with Facebook, it will cause an error requiring account linking.
  • User signs in with a trusted provider, then signs in with a different trusted provider with the same email (for example, Apple followed by Google). Both providers will be linked without errors.

You can manually set an email as verified by using the Admin SDK, but we recommend only doing this if you know the user really does own the email.


Why not turn off One account per email address

By default, the setting One account per email address is active as @Deva wrote. But, unchecking this means that there are two different accounts ( User UIDs ) for the same email. One via Email/Password and one via Google Authentication . They will have separate User UIDs in Firebase Auth , so that may confuse you. Furthermore, if you manually link in your app two User UIDs , this creates a security hole: Someone can create an account without email verification to get access to an existing account. So don't do that.


Related StackOverflow questions and links

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM