Firebaseui-web: Do Not Require "Sign In With Google" to sign in with email (screenshots)

Created on 30 May 2018  路  10Comments  路  Source: firebase/firebaseui-web

Facebook and Facebook Messenger's In-App browser do not support Google's OAuth. It throws an error on Google's end during the redirect saying it doesn't support that app. disallowed_useragent (iOS Only - works fine on android).

For this reason, when I detect the Facebook in-app browser, I force my users to login with email / password. (I do not include the Google login when Firebaseui initializes)

This works great for new users, they can create / sign in with email and password fine.

The problem is when users have previously created an account with their Google login, and then try to login through the Facebook in-app browser on iOS. They can try using the email / password authentication method, but then, Firebaseui tries to force this user to "sign in with google", which subsequently throws the disallowed_useragent error.

How can you prevent this from happening, and merge the email / password auth account with the google account? If you create an account with email / password first, and then use Google to login, it works fine. Why not also work the other way around?

        // FirebaseUI config.
        var firebaseui = require('firebaseui');

        // Facebook browser does not support Google Auth
        // Check for Facebook browser
        let browser = null;
        if(typeof navigator !== "undefined" && typeof window !== "undefined") {
            var ua = navigator.userAgent || navigator.vendor || window.opera;
            if ((ua.indexOf("FBAN") > -1) || (ua.indexOf("FBAV") > -1)) {
                browser = "facebook";
            }
        }

        // Conditionally build signInOptions
        let signInOptions = [];

        // Add Email / Password Auth
        signInOptions.push(firebaseAuth.EmailAuthProvider.PROVIDER_ID);

        // Add Google Auth only if not Facebook browser
        if(browser !== "facebook") {
            signInOptions.push({
                // Google provider must be enabled in Firebase Console to support one-tap sign-up.
                provider: firebaseAuth.GoogleAuthProvider.PROVIDER_ID,
                // Required to enable this provider in one-tap sign-up.
                authMethod: 'https://accounts.google.com',
                // Required to enable ID token credentials for this provider.
                // This can be obtained from the Credentials page of the Google APIs
                // console.
                clientId: 'XXX'
            })
        }

        var uiConfig = {
            signInOptions,
            callbacks: {
                signInSuccessWithAuthResult: function(authResult, redirectUrl) {
                    // Anything we want to happen after signin success

                    // Store user data in the redux store
                    storeUserDataAction(authResult.user);

                    // Auto-send verification email if we have not already done so
                    autoVerifyEmailAction();

                }
            },
            // Terms of service url.
            tosUrl: 'XXX',
            // Required to enable one-tap sign-up credential helper.
            credentialHelper: firebaseui.auth.CredentialHelper.GOOGLE_YOLO
        };

        // Initialize the FirebaseUI Widget using Firebase.
        // Checks to see if we have an existing instance, if not, creates a new one
        var ui = firebaseui.auth.AuthUI.getInstance();
        if (!ui) {
            ui = new firebaseui.auth.AuthUI(firebaseAuth());
        }

        // Auto sign-in for returning users is enabled by default except when prompt is
        // not 'none' in the Google provider custom parameters. To manually disable:
        ui.disableAutoSignIn();

        // The start method only if we're done checking the authState
        ui.start('#fbui-container', uiConfig);
    }

firebaseauthui

disallowed

question

All 10 comments

This is a known issue. If you previously created a Facebook account and then try to sign in with email/password, you will be asked to sign in with Facebook. Even if you want to force email/password sign in to the same account, the user would need to prove ownership of the original Facebook account before linking both accounts (provided you have the "one account per email" setting enabled).

@bojeil-google I'm not sure I follow the logic of not being able to link Email to an existing Google sign-in. The only two providers in this scenario are GoogleAuthProvider and EmailAuthProvider.

If the user has signed in with GoogleAuthProvider as [email protected], then Google has already verified ownership of the email address, right? So then if the user later attempts to sign in with the EmailAuthProvider, the accounts/providers should be able to be linked since the email address effectively can be used as the verified key for tying the accounts together, right?

@boon4376 originally provided the example of doing this within the Facebook webview... since the Google Auth provider isn't allowed in a webview, his idea was to allow users to workaround this by linking Google and Email accounts so users would at least have _some_ option for logging in.

The same concept could be applied as a workaround for https://github.com/firebase/firebase-js-sdk/issues/77 where Google login can't be used when an webapp is Added to Homescreen in iOS. Without this form of linking, users can't login to a service authenticated using FirebaseUI Web at all under certain scenarios.

FirebaseUI will always show you an existing method of sign in associated with an existing account. So if you had a Google account already registered and then try to sign in with email, you will be redirected to use google to sign in. For most cases, this is the desired behavior. If you are trying to use this as a workaround for google sign in not working in a homescreen from iOS, then it won't work. You would need to add your own password linking logic after user create a google sign in account via firebaseui. So the next time, the user will be allowed to sign in with email.

@bojeil-google thanks for the reply. I went ahead and worked up account linking, but there appears to be a problem when using the FirebaseUI Web with an account which has a Google and Email provider linked using the _same email address_.

The accounts get linked as expected and I can login with either the Google Account or the Email address (or any other linked type like Phone). What is odd is that after the providers are linked, if the password reset feature is used in FirebaseUI Web (for the email account), it will unlink the Google provider.

What's more, if you then try to login with the Google provider using FirebaseUI Web, it will automatically re-link the Google provider!

@joshualyon This is the expected behavior. The reason is resetting password indicates the account is compromised sometimes. So unlinking other providers is to prevent hacker from accessing your account using other providers.

Following up on my previous comment, I went about coding a custom sign-in / sign-up interface and found that the issue with an Email Password Reset unlinking the Google account seems to be something more fundamental to the Firebase Auth password reset process.

Similiar to wti806's response, I found a Stack Overflow response which appears to be by @bojeil-google wherein in was commented that the unlinking is an intentional behavior to allow the user to recover their account in the case that it was hijacked and modified by another unverified user.

I'm not sure I understand that logic here though? Even after an automatic unlink due to a password reset, if we sign-in with a Google account again it automatically re-links the providers. So how is this helpful in a hijacking scenario?

Edit: Perhaps the unlinking logic is just a bit more broad than my specific use cases? I suppose I could understand the scenario where a password based account was hijacked and once the attacker was logged in they linked a social media account with a completely different email address. Depending on that website's implementation, if the site didn't show the account linking within their UI, the user might never know about the maliciously linked account and even after a password reset they would think their account was now safe when the attacker still had a backdoor. I still wonder how this applies when the _same email_ is used in an Email provider and Google provider though. The Google provider should have confirmed ownership of the email address... and even if the concern was that the Google account could have also been compromised, it seems like Firebase automatically relinks the accounts anyway when the Google account (with the same email address) is used to login again.

Is this behavior documented somewhere? I checked the reference for confirmPasswordReset but didn't see anything there.

This is all expected behavior. There are 2 issues here that are unrelated:

  1. password reset unlinks existing providers as @wti806 explained to help users recover from possible account modification (unauthorized providers being linked).
  2. Google sign in overwriting unverified email/password account. Check this post why this happens. This prevents malicious users from creating an account with another user's email. To avoid this behavior, you need to verify the user's email after the account is created to confirm ownership of that email so the next time Google is used to sign in, the email/password is preserved.

Thanks for the additional details! I think we are getting closer, but there's still a disconnect! My point is specific to the combination of Email provider and Google provider with the same email address.

I can understand the password reset unlinking a third-party social account since those are outside the control of Google and might not actually be validated email addresses (except for within their trusted provider domains)... but I'm specifically referring to Google and Email accounts using the same email address which is verified by Google.

So if I am signed in with an email address using email/password which is in the trusted domain for the Google provider, (1) why is Google provider automatically unlinked if it is the trusted provider for that email domain and (2) what's the point of unlinking the account if signing in with the Google provider just automatically relinks itself (note that I'm referring to automatic linking - not overwriting the email/password as you mentioned)

The second point about automatic relink is probably more salient here. What is the point of unlinking an account if it's just going to be automatically relinked when the user signs back in with the trusted provider? Again, I can understand unlinking for non trusted providers... but if you are just going to automatically relink the account when the person signs in with the trusted provider, I don't see how unlinking it in the first place adds any value?

We don't determine logic based on the history of changes made on an account.
The logic is straightforward. I will repeat it one more time:

  1. Providers are unlinked on password reset because we don't know if the account was hijacked and modified by adding new providers. It is even possible to update the email (we send an email change revocation to revert that to the original email). The hijacker could link their own Google account. That's an additional reason why all providers should be unlinked.
  2. Signing in with a verified provider like Google will always overwrite an unverified email. Because we have no idea the account was created by the real owner of the email. If this is an issue, then you should ensure the email is verified to prevent this. When the email is verified, the accounts are merged without any additional friction.

I agree there are inconveniences in the above, but this offers the security needed to protecting accounts from being compromised.

I appreciate your reiteration.

What I'm saying is I don't see how step 1 is adding any security _in this specific case_. In step 2, the account is automatically relinked. So what was the point of automatically unlinking it if it can just be _automatically_ relinked?

Was this page helpful?
0 / 5 - 0 ratings