firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.78k stars 877 forks source link

Safari onAuthStateChanged stuck when multiple tabs open #8019

Open ReinoutStevens opened 5 months ago

ReinoutStevens commented 5 months ago

Operating System

iOS

Browser Version

Safari

Firebase SDK Version

10.7.2

Firebase SDK Product:

Auth

Describe your project's tooling

NextJS app with Firebase loading as a dynamic component / separate chunk

Describe the problem

There is a problem with the onAuthStateChanged event callback in Safari on iOS ( or just with authentication in general ). The callback is not always invoked when the app has started, and as a result, the user is stuck while our app is waiting for firebase to finish. More specifically, the callback can also be invoked unreasonably late, as if firebase is stuck somewhere.

Initially, we could not reproduce this reliably, and have only seen it ourselves a couple of times. As such, we have added an analytics event in the onAuthStateChanged callback to trigger when and how often firebase loads. We just found out that the behavior can be triggered by having multiple tabs open to the same site, and after several hours, opening a new tab will get stuck.

Not loading:

Browser Sessions Loading Sessions Not Loading Ratio
Chrome 16311503 4512 0.027 %
Firefox 734236 59 0.008%
Safari 2053968 22709 1%

Delayed loading:

For sessions in which firebase loads we looked at the different percentiles, median and average. Timings are in ms

Browser avg time 5pct 25pct median 75pct 95pct
Chrome 1763 2 10 133 497 2239
Firefox 3097 1 3 9 134 911
Safari 427408 1 7 77 371 16964

Yes, that average for Safari is correct. For a small subset of users the onAuthStateChanged callback takes an insanely long amount of time to get called.

We have reworked our application a bit to try to not give these users an awful experience. For users where we suspect that firebase is not loading, but that still stick around long enough, we notice that firebase can eventually load after some time.

Timings are in seconds

Browser avg time 5pct 25pct median 75pct 95pct
Chrome 197 0 5 18 41 163
Firefox 339 0 9 29 76 259
Safari 7578 0 31 235 1700 38987

Chrome and Firefox timings can be explained due to slow devices or networks ( as we're quite a heavy site in terms of downloading assets ), but Safari has other problems.

Steps and code to reproduce issue

We recently ( read, last night ) finally found out that you can get this behavior by having multiple tabs open of site for a couple of hours ( we managed to get it after waiting 2h, we don't know if you can get it sooner ), and then opening a new tab to the site. This tab will be stuck. Refreshing any of the other tabs will also result in them being stuck. Closing some of the tabs will result in a stuck tab to become unstuck.

We haven't looked deeper into how long tabs need to be open, or whether it's a specific tab you need to close. In case it matters, we've had it happen on a device where we never logged in on firebase, and a device where we had previously logged in. In both cases after a couple of refreshes firebase loaded just fine.

The code boils down to:

const [userLoading, setUserLoading] = React.useState(false);

useEffect(() => {
    const cleanup = onAuthStateChanged(firebaseAuth, (newUser) => {
       // callback gets never invoked
       setUserLoading(false);
   };
  return cleanup;
}

We have tried other implementations using authStateReady ( which under the hood also use onAuthStateChanged ), where the same problem occurs.

Related issues: https://github.com/firebase/firebase-js-sdk/issues/2167

ReinoutStevens commented 2 months ago

I dislike bumping issues by adding a comment, but this issue is still affecting our site. We're adding notices to our users when firebase doesnt load within a certain timeframe to kill other tabs, but this is a really abysmal user experience.

jacobgram commented 3 weeks ago

@ReinoutStevens I believe we are facing the same issue. We was using onAuthStateChanged then tried authStateReady. Both have the same issue. Have you found a solution for this? Do you mind share if you are using signInWithPopup or signInWithRedirect

ReinoutStevens commented 3 weeks ago

No. We basically added a timeout, and when firebase doesnt resolve within that limit we show a popup to the user telling him to reload, and close other tabs of our website. We are using signInWithPopup

jacobgram commented 3 weeks ago

Thanks for sharing:

We just found out that the behavior can be triggered by having multiple tabs open to the same site, and after several hours, opening a new tab will get stuck.

I was able to reproduce it.