firebase / firebase/firebase-js-sdk

Safari onAuthStateChanged stuck when multiple tabs open

Open
#8,019 16 comments 4 reactions 0 assignees View on GitHub
api: auth needs-attention question
Dominant language
TypeScript
Stars
5.1k
Forks
1k
Avg merge
2d 21h
Merged PRs (30d)
37

Description

### 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

Contributor guide

Open the contributing guide

Research direction

Start with the Auth onAuthStateChanged and authStateReady entry points described in the issue, then try the multi-tab Safari-on-iOS reproduction after tabs remain open for several hours. Compare the behavior with the related issue 2167; done means a newly opened or refreshed tab reliably invokes the auth callback instead of remaining stuck.

Written by the indexing model from the issue text.

Assessment

Tech stack
ios, nextjs, typescript
Domain
authentication, mobile-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.