firebase / firebaseui-web

FirebaseUI is an open-source JavaScript library for Web that provides simple, customizable UI bindings on top of Firebase SDKs to eliminate boilerplate code and promote best practices.
https://firebase.google.com/
Apache License 2.0
4.58k stars 1.06k forks source link

Firebase UI Signin / Signup #665

Open togonow opened 4 years ago

togonow commented 4 years ago

I've recently switched from Auth0 to firebase authentication and slowly migrating some services to firebase store. Reason is Auth0 is over engineered and like how firebase is simple and streamlined. Except when it comes to the firebase ui widget. It's mind boggling how the developers came to the idea of combining the login / sign up into a single form, and i see it's been multiple years this issue is being ignored as if all email/password login/signup flows always starts with only an email field.

I've included a snippit from multiple popular websites (Amazon, facebook, Auth0, gmail, youtube) including your parent company Google how they handle a login / signup page. None of them combine the login / signup page into email input only.

I wish the team looks into this issue as now i have to code implement the web authentication page from scratch to provide the separate login / sign up funcitonality.

bojeil-google commented 4 years ago

Hey @togonow, FirebaseUI was optimized for mobile usage and for minimizing the friction during sign up.

  1. It supports federated sign in. With federated sign in there is really no sign in or sign up flow. Users click a button and the user is signed in. Note that all the screenshots you provided are native email/password sign-in or sign-up.
  2. Nascar screen is the first screen to show up. On a mobile device, no typing is needed. The user clicks the button and is signed in.
  3. Firebase Auth supports account linking (single account per email). If a user forgets they previously signed in with Google and try to sign in with Facebook using the same email, FirebaseUI will automatically link both accounts preventing accidental creation of 2 accounts for the same user.
  4. By asking the user for the email first in the sign in with email flow, we can figure out whether to sign in or sign up the user or whether to even sign in the user with Google or some other provider (in case the user forgot they used Google to previously sign up).

These are just a couple of ways Firebase Auth optimizes the user sign in / sign up experience.

That said, we do understand some of the different needs and opinions on this experience. We are open to adding more variations on the sign in / sign up experience and would like to support them long term.

manterfield commented 4 years ago

@bojeil-google All of the above considers this from the perspective of the developer, rather than the user. As the developer, I'm comfortable with the concept and why it works that way because I added it to my site/app in the first place.

As a user, if I see a load of buttons (including email login) and they all say 'Sign in' but there's no option for signup, then I assume I'm in the wrong place and continue looking for the registration flow for the site/app.

The main offender from my perspective is the email + password login button having 'Sign in with email'. The others are third party services, as such I can reason that those options must use existing accounts, that's not true for what seems like a 'traditional' login.

If I did click the email sign in button just to check it out, the next title also refers to it as 'sign in with email'. No hint I might be able to create an account. It's not until I enter a new email address that the flow reveals 'Create an account' as a title.

Perhaps I've missed options for configuring this, but if so the docs aren't obvious as I've scoured for a while now. It's quite a confusing flow IMO and without explainer text added outside of the UI lib I'm not sure many of my users would make it through using email + password for signup.

About7Sharks commented 4 years ago

@manterfield Came here looking for an option to display a sign up button. I think only having sign in options really confuses the end user.

johngrimsey commented 4 years ago

In my view @manterfield is absolutely correct.

Whilst we appreciate the technical decisions, we are left without the ability to decide to make things clearer to users should we wish. Short of adding an extra bit of blurb close to the login widget, which would potentially create a confusing contradiction of sorts.

Please consider that so many users of different ages and abilities use this sign in. Some people will spend three seconds looking for a button or link that says register or sign-up and give up. Others may simply lose confidence in the app as they continue.

This could even be affecting conversion for some audiences (I have no evidence, just throwing it out there). At least, I'm worried about that enough to consider coding the whole thing manually. Hell it even confused me as a developer the first time I integrated it, where was the "register" mode?

It would be very good to have the option to show an explicit link that says "Create account" or "register" as the screens in @togonow's post demonstrate.

Thanks!

ultraGentle commented 4 years ago

How about changing the button text to sign in / sign up?

Or allowing that minor customization as an option.

sgraham3311 commented 4 years ago

@manterfield and @johngrimsey are completely correct. This is a showstopper for me. I would need to code my sign in/sign up flow from scratch before I can release to the public if this not option. As a developer the library is great and allows me to focus on building my app but this is a pretty big gap IMO and I am going to have to circle back and code this from scratch before I release if there is no way to have a separate registration option.

togonow commented 4 years ago

Hey @togonow, FirebaseUI was optimized for mobile usage and for minimizing the friction during sign up.

  1. It supports federated sign in. With federated sign in there is really no sign in or sign up flow. Users click a button and the user is signed in. Note that all the screenshots you provided are native email/password sign-in or sign-up.
  2. Nascar screen is the first screen to show up. On a mobile device, no typing is needed. The user clicks the button and is signed in.
  3. Firebase Auth supports account linking (single account per email). If a user forgets they previously signed in with Google and try to sign in with Facebook using the same email, FirebaseUI will automatically link both accounts preventing accidental creation of 2 accounts for the same user.
  4. By asking the user for the email first in the sign in with email flow, we can figure out whether to sign in or sign up the user or whether to even sign in the user with Google or some other provider (in case the user forgot they used Google to previously sign up).

These are just a couple of ways Firebase Auth optimizes the user sign in / sign up experience.

That said, we do understand some of the different needs and opinions on this experience. We are open to adding more variations on the sign in / sign up experience and would like to support them long term.

Hey @bojeil-google sorry for the toooo late reply here are some federated authentication sign in workflow with clear separate sign in / create account which eliminate confusion and typo accounts creation.

Screen Shot 2020-04-24 at 5 12 32 PM Screen Shot 2020-04-24 at 5 05 08 PM Screen Shot 2020-04-24 at 5 00 34 PM
dandv commented 4 years ago

After two years of using both Firebase Auth and Auth0, I can only agree with @manterfield: Auth0 is way over engineered and complex, and the only reasons I'm using it, are because firebaseweb-ui is incredibly slow at social logins, and this confusion between signin in and signing up.

w0nche0l commented 4 years ago

I'm using the react version of this library, and I'm getting around this with the HACKIEST HACK ever:

If the user is on the signup page, I do this every frame:

    if (props.isSignUp) {
      const texts = document.querySelectorAll(
        ".firebaseui-idp-text-long, .firebaseui-title"
      );
      for (let i = 0; i < texts.length; ++i) {
        const item = texts.item(i);
        if (item?.textContent?.includes("Sign in")) {
          item.textContent = item.textContent.replace("Sign in", "Sign up");
        }
      }
    }

Has many problems, but better than the confusion that I see in both analytics and anecdotally when people click "Sign Up" and get sent to a screen that says "Log In".

I think that if it is too big of an ask to support actual different flows for Signin/Signup, then it would be nice if we could at least set the text to a certain value?

kmjennison commented 4 years ago

To share our experience: the inability to separate "sign up" from "log in" causes us a lot of user support headaches and overhead. We consistently hear from users who accidentally create a new account (using a different email address from their original account) and then think the app is malfunctioning or has lost their data.

In this case, simply changing text to "sign up" wouldn't be enough. We'd ideally want the "log in" flow to error if the user doesn't already exist. An option (e.g., allowExistingUsersOnly) to cause nonexistent accounts to throw an error, even without any associated UI, would help a lot.

To an extent, #99 is related because Firebase would need to check if a user exists rather than automatically create a new one.

togonow commented 4 years ago

Hey @bojeil-google , would like to hear from you after others input. Hope you are safe and sound.

tadhunt commented 4 years ago

Here's my version which is based on on @w0nche0l's version, but extended to handle updates when the firebase ui decides to update the elements itself. Examples include hitting the cancel button on the email signup, which brings you back to the initial view. Also, if you have multiple identify providers configured, every path back to the toplevel "a pick-an-identify-provider" view is now covered. This is grossness piled on grossness.... but it gets the job done.

const authuiObserver = new MutationObserver(function(mutationsList, observer) {
    const texts = document.querySelectorAll(".firebaseui-idp-text-long, .firebaseui-title")
    for (let i = 0; i < texts.length; ++i) {
        const item = texts.item(i)
        if (item?.textContent?.includes("Sign in")) {
            item.textContent = item.textContent.replace("Sign in", "Sign up")
        }
    }
})

authuiObserver.observe(REPLACE_WITH_PARENT_ELEMENT, { attributes: true, childList: true, subtree: true })
mlh496 commented 4 years ago

Hello @bojeil-google

Are there any plans to tackle this on the Q3 OKRs for the Firebase team? If not, we'll build our own stop-gap solution.

Also, one thing to consider is that Flutter for Web is in beta. And since Flutter plays nicely with Firebase, I imagine a lot more devs will run into this same problem soon. Just food for thought...

Thank you!

davidstackio commented 4 years ago

As of v4.6.1, you can customize the button labels:

signInOptions: [
    {
      provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
      fullLabel: "Sign up with Google"
    },

What I ended up doing was having separate /signin and /signup pages with the two different sets of button labels, with links on each page to the other. It also worked out in my case since I have a "sign up step 2" where I ask for more info (first name, phone, time zone, etc), and this flow works perfectly for that use case.

From a developer point of view, it's a bit redundant, but from the user's perspective, this kind of flow is the norm.

AustenLamacraft commented 4 years ago

This is a big improvement, though I note that when I click through to sign up with email it will still say "Sign in with email" on the form

ubragg commented 4 years ago

Just to add a data point here, I run a seasonal service that users log into only about once a year, and because there is no difference between signing in and signing up, and one year is long enough that most people forget which account they used last time, of the first 10 users to try sign in this year, 3 of them accidentally created a new account with a different email, and thought that all their data had been deleted.

Unfortunately, simply making the button able to say "sign in" or "sign up" isn't sufficient, because that wouldn't have solved my issue at all. It does need to have that, but the "sign in" flow should only proceed if an account already exists, and let them know when it doesn't, so if they know they have an account, they can deduce that they just picked the wrong one. I have been following this thread for a while and already knew that this issue is a pain point, but now with some real data, I'm realizing it's a pretty major pain point.

@togonow - thank you for filing this and showing tons of examples of how this should and does work on other sites that have already solved this issue.

jamesw6811 commented 3 years ago

@AustenLamacraft

This is a big improvement, though I note that when I click through to sign up with email it will still say "Sign in with email" on the form

This can be fixed using CSS overrides like this:

.firebaseui-card-header {
  display: none;
}

However, @ubragg is correct in that the real problem is not throwing an error when someone is intending to sign in and accidentally creates an account.

birdlavv commented 3 years ago

Expanding the answers given by @jamesw6811 & @dhstack

I ended up using separate /login /sign-up pages to meet user expectations and avoid confusion.

These CSS overrides replace the default header

.firebaseui-title {
  display: none;
}
.firebaseui-card-header {
  padding-bottom: 16px;
}
.firebaseui-card-header::after {
  content: 'Sign up with email';
  color: rgba(0, 0, 0, 0.87);
  direction: ltr;
  font-size: 20px;
  font-weight: 500;
  line-height: 24px;
  margin: 0;
  padding: 0;
  padding-bottom: 0px;
  text-align: left;
}
Screen Shot 2020-12-04 at 5 04 34 PM Screen Shot 2020-12-04 at 5 05 11 PM

It works for now, but this really should be natively supported to prevent breaking changes if changes to the css classes used are made.

BenHayat commented 3 years ago

I have read this entire thread and I'm totally shocked to see that Google is not providing us two separate user flow to Sign up (register NEW Account) and to Sign-in (Log in EXISTING users) when it comes to email/password option. Every vendor offers this flow to eliminate user's confusion.

Google wants us to use Firebase-UI, then please make it look like a standard Auth UI.

So, could someone from Google (with github User Info to confirm employee of Google), offer guideline, when a NEW user is going to create an account with PASSWORD? How do we program it that is crystal clear to user that she is Signing up as NEW user?

I look forward to an official guidelines from Google Team on this matter Thanks!

sam-gc commented 3 years ago

Hi folks, we are aware of this feature request and we are tracking it internally (b/175809321), but beyond that we have no updates for now.

dytra commented 3 years ago

As of v4.6.1, you can customize the button labels:

signInOptions: [
    {
      provider: firebase.auth.GoogleAuthProvider.PROVIDER_ID,
      fullLabel: "Sign up with Google"
    },

What I ended up doing was having separate /signin and /signup pages with the two different sets of button labels, with links on each page to the other. It also worked out in my case since I have a "sign up step 2" where I ask for more info (first name, phone, time zone, etc), and this flow works perfectly for that use case.

From a developer point of view, it's a bit redundant, but from the user's perspective, this kind of flow is the norm.

this method works if you use in production, the label won't affect if you in development

bojeil-google commented 3 years ago

@dytra is correct. I explained some of the reasoning behind the current setup earlier in this thread. We try to optimize for the following in our UX:

For the most of it, this works for many of our customers. However, we do understand that our UX flow may not work for others. There are different needs and variations of sign in / sign up flows. We will try to cater to as many as we can but we may not be able to address all of them.

As a result, we do offer some ways to customize the flow. For example you can use the following new customizations per provider: fullLabel to customize the full button label, iconUrl to customize the icon URL, providerName if you just want to customize the name of the provider, buttonColor to customize the button background color, etc. You can even include 2 email providers one with sign up label and another with sign in. I believe that should be possible.

We even provide a callback to trigger on page change. We don't document this but you can use it at your own risk (we do discourage DOM manipulation using that callback).

// Do not manipulate FirebaseUI DOM as it will break it.
'uiChanged': function(fromPageId, toPageId) {
  // UI changing from fromPageId to toPageId
}

Hopefully, this addresses some of your concerns while we prioritize supporting new flows for this.

ubragg commented 3 years ago

@bojeil-google Thanks for the update and the reassurance that new flows are being considered.

Perhaps you're considering this, but a pretty simple idea that might address many of the remaining issues might be to simply add a couple new options in signInOptions like "requireExisting" which would cause the action to fail if an account already exists and "requireNew" which would cause the action to fail if an account already existed. Then developers could choose to use them or not, but there would at least be a simple option for enforcing semantic differences between signing in and signing up beyond just changing the string.

jaunt commented 3 years ago

It's amazing to me, but we're also seeing a significant percent of users who mistype their email, and end up creating an account by mistake. Would love a "requireExisting" parameter as suggsted by @ubragg

let uiConfig = {
  signInFlow: "popup",
  requireExisting: true,
  ...

me.ui = new firebaseui.auth.AuthUI(firebase.auth());
me.ui.start("#firebaseui-auth-container", uiConfig);
jaunt commented 3 years ago

Note: the work around I came up with today is as follows, based on the handy uiChanged callback posted above. We'll see if it gets through testing. In the code below, "newNotAllowed" is a property I pass to my sign in wrapper component, when I don't want new users to be created. My "newUnexpected" function reroutes to a separate screen, thereby closing the sign in process.

              uiChanged: (fromPageId, toPageId) => {
                // UI changing from fromPageId to toPageId
                if (this.newNotAllowed && toPageId == "passwordSignUp") {
                  this.newUnexpected(
                    "Could not find an account with that email address.  Please try again.",
                    true,
                    false
                  );
                  return;
                }
              },
pankaj9296 commented 3 years ago

Note: the work around I came up with today is as follows, based on the handy uiChanged callback posted above. We'll see if it gets through testing. In the code below, "newNotAllowed" is a property I pass to my sign in wrapper component, when I don't want new users to be created. My "newUnexpected" function reroutes to a separate screen, thereby closing the sign in process.

              uiChanged: (fromPageId, toPageId) => {
                // UI changing from fromPageId to toPageId
                if (this.newNotAllowed && toPageId == "passwordSignUp") {
                  this.newUnexpected(
                    "Could not find an account with that email address.  Please try again.",
                    true,
                    false
                  );
                  return;
                }
              },

@jaunt The workaround you suggested seems good. can you please share the this.newUnexpected function definition?

jaunt commented 3 years ago

@pankaj9296 newNotAllowed is super implementation dependant. For example, I'm using Vue, so essentially that function in my case changes my SPA router view, leading to a destroy call to my facebook-ui vue page, which cleans up firebase-UI. Unless you are using Vue in the exact way I am, it would not be helpful :-)

pankaj9296 commented 3 years ago

@jaunt Got you, thanks. I'm using next.js btw.

zehawki commented 3 years ago

I'd like to mention that there is merit in the current format... The first step says "sign in with email". One enters an email ID and the form changes to "Create account" for new account creation and "Sign in" for existing account.

One of the things that is constantly being mentioned in this issue is "how does a user know if they are creating a new account, esp if they have forgotten the email ID" -> they know coz the form affordances have changed.

This also makes sense since there is a move towards passwordless flows, where it makes no difference whether its signup or signin...

jaunt commented 3 years ago

I'd like to mention that there is merit in the current format... The first step says "sign in with email". One enters an email ID and the form changes to "Create account" for new account creation and "Sign in" for existing account.

One of the things that is constantly being mentioned in this issue is "how does a user know if they are creating a new account, esp if they have forgotten the email ID" -> they know coz the form affordances have changed.

This also makes sense since there is a move towards passwordless flows, where it makes no difference whether its signup or signin...

I think the merits have been discussed quite a bit in the conversation above, but I'd agree that for a watchful and patient user, the current behaviour can work. My issue as described in the conversation has to do with users that perhaps make a typo when signing in, and aren't watching the screen closely, and thereby accidentally create a new account. Also there is the problem of describing a button to a new and nervous user, that the button can both sign in and create a new account. What do you call such a button? If your product is geared for very technical users, perhaps you won't have issues. My customer base definitely runs into problems.

azrinsani commented 3 years ago

Wow, can't believe this hasn't been resolved yet. Its such a big issue. I've decided to abandon firebase for now.

abstraktion-io commented 3 years ago

Yes, and using the sign-in button that finishes into signup without consent is a privacy issue: is there a way to handle this?

yeldarby commented 3 years ago

For what it's worth, we've been doing user testing sessions and almost every user is confused by this UI (including technical users with a development background).

They spend several seconds searching for a "sign up" button and then eventually come around to "well maybe I just need to use the sign in even though I don't have an account yet?" and click it with very little confidence that they're doing the correct thing.

zehawki commented 3 years ago

Yes, and using the sign-in button that finishes into signup without consent is a privacy issue: is there a way to handle this?

So what about social signin ie "continue with google / facebook / github / twitter"? Social signin makes no differentiation between "signin" and "signup" events - both are seamless and a single click moves one into account creation automatically.

abstraktion-io commented 3 years ago

In term of UX I did it that way https://fabric.abstraktion.io/

perelin commented 3 years ago

Hi, so what is the recommended best practice to deal with the "user typo in email address creates new account by accident" issue?

perelin commented 3 years ago

Also, whats the best practice to handle GDPR required consent checkboxes (eg for marketing opt-ins) that only need to be shown and validated during signup?

perelin commented 2 years ago

Has any one experience with my last two questions?

Hi, so what is the recommended best practice to deal with the "user typo in email address creates new account by accident" issue?

Also, whats the best practice to handle GDPR required consent checkboxes (eg for marketing opt-ins) that only need to be shown and validated during signup?

simonness commented 2 years ago

It seems there are two main usability issues raised here:

+1 on configurable native support for this though. I'd quite like to be able to present a UI with the email and password text boxes both showing on initial entry if the email/password provider is enabled, above any social login options and a "Create new account" link.

perelin commented 2 years ago

I would like to add the issue of checkbox values. Newsletter opt-ins, legal stuff, etc [1]. It would great to have the possibility to transmit custom parameters with the authentication request and get them back afterwards.

[1] Examples

Apple Screenshot 2022-01-14 at 13 59 43

Spotify Screenshot 2022-01-14 at 13 56 02

Dropbox Screenshot 2022-01-14 at 13 52 25

jaunt commented 2 years ago

I want to mention a problem that is popping up more and more for my users, and it causes severe confusion and wastes a lot of our customer support time:

Existing email account holders go to the sign in screen and maybe forget that they used email and end up clicking "sign in with google" or "sign in with facebook". This instantly creates a brand new account for them (because the email of their social account doesn't match their email account) and they get very confused.

I wonder if third party sign-in is picking up for non technical users in general, and they are forgetting which sites they used it on, or think that it will "just work" if they switch to using it.

As far as I understand the new "prevent account creation" flag added recently is only for email sign in and won't work for social providers.

The only workaround I can think of is to track when a person is on my signin page, and if a new firebase account is the result, send them to a failed page and delete that new account. Is it true that if I migrated to google "Identity Platform" I would be able to use a blocker to achieve this before the firebase account gets created?

Update

I have implemented the method mentioned above. When a user goes through my sign-in flow, and they click sign in with email, I watch "uiChanged" and I cancel the sign-in if it gets to "passwordSignUp". For 3rd party signin like google and facebook, in signInSuccessWithAuthResult I make a call to my backend to see if the firebase ID exists as a DB user on my end and if not, I delete the firebase ID and notify my UI. If I had to delete it, I cancel the sign-in process.

This issue had been amplified for us thanks to this: https://github.com/firebase/firebase-js-sdk/issues/4256, as I've had to disable social sign in on embedded browsers. So a facebook user finding our ad signs in with email in the embedded browser, then next time they visit us from a real browser, they click sign in with facebook forgetting they used email, and if their facebook email didn't match their sign in email, a new account was getting created and all out confusion would ensue.

tiga05 commented 2 years ago

Hello from the future.

I wanted to implement the login screen in my app and ran into the exact same problem.

I searched on the internet how to create an account from this screen. But there is nothing mentioned in the offical firebaseUI web documentation. Then I came up with the idea of entering an email that is not yet registered.

And then I found this nice thread about this issue.

So please: fix it. None of my users will find out how to register....