Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onAuthStateChanged hangs on startup at initializing current user step #8481

Open
GaurangTandon opened this issue Sep 5, 2024 · 5 comments
Open

Comments

@GaurangTandon
Copy link

Operating System

Windows

Environment (if applicable)

Chrome 128

Firebase SDK Version

10.11.0

Firebase SDK Product(s)

Auth

Project Tooling

MV3 Chrome extension service worker built using webpack

Detailed Problem Description

Problem

onAuthStateChanged() hangs on extension service worker startup and then remains hanged until the extension service worker is restarted (either by restarting the browser or by manually reloading the extension). Note that we are using indexeddb persistence so we expect the Firebase instance to get logged in automatically whenever the service worker restarts.

This hang is slightly more frequent compared to the other one in PersistenceManager. We suspect the issue happens more often when the user logs into computer in the morning of a workday. In that case, the user's Firebase ID token from yesterday has expired. Based on that, and based on the logs given below, we suspect the hang is when Firebase is regenerating the ID token. We are not sure why that is, maybe due to network conditions? Our hypothesis could be wrong though.

Logging details

We added logging into the underlying @firebase/auth package using npx patch-package, and got the hang on this case:

/// in _initializeWithPersistence
tbLog('IWP: iniatilizing current user'); // <-- this line got printed
await this.initializeCurrentUser(popupRedirectResolver);
tbLog('IWP: finished current user'); // <-- this line never got printed

/// in initializeCurrentUser
if (futureCurrentUser) {
  tbLog('ICU: c1'); // <-- this line got printed
  return this.reloadAndSetCurrentUserOrClear(futureCurrentUser); // <-- hanged here
}

PS: Let us know if you need additional logging inside the Firebase Auth package, and what exactly. It can take us a few days to get the data though.

Steps and code to reproduce issue

We have roughly the following setup:

import { getAuth, onAuthStateChanged, } from 'firebase/auth/web-extension';

const firebaseApp = initializeApp(firebaseConfig);
const firestore = initializeFirestore(firebaseApp, {
  experimentalForceLongPolling: true
});
onAuthStateChanged(getAuth(firebaseApp), (user) => {
  console.log(user);
  if (user) {
    enableIndexedDbPersistence(firestore, { forceOwnership: true });
  }
}});

Note that we are using the web-extension entrypoint into firebase/auth. Note that we initialize persistence after auth has enabled. I'm not sure if it should be the other way around, I couldn't find any official docs around it, or if that matters at all.

I have attached the patch file generated using patch-package.
@firebase+auth+1.7.1.patch

@GaurangTandon GaurangTandon added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Sep 5, 2024
@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@jbalidiong jbalidiong added api: auth needs-attention and removed needs-triage new A new issue that hasn't be categoirzed as question, bug or feature request labels Sep 5, 2024
@dlarocque
Copy link
Contributor

dlarocque commented Sep 10, 2024

Thanks for reporting this issue! To help me reproduce this and confirm it as a bug, could you please share how you're setting up the service worker in the web extension (manifest.json, webpack.config.js), along with the full usage of firebase in the service worker file?

Since the other issue originates from the same project this would be useful for reproducing that as well.

@GaurangTandon
Copy link
Author

@dlarocque Manifest file: manifest-for-firebase-team.json
We're using webpack to build the file js/background.js (included in service worker section of the file) - which makes calls to firebase. The config file:

module.exports = /** @type { import('webpack').Configuration } */ ({
  externals: /^\.\.\/resources\/\w+\.main\.js/,
  externalsType: 'module',
  mode: 'production',
  experiments: {
    outputModule: true,
  }
});

and the command line call:

npx webpack <filepath> --output-path <directory> --output-filename <filename> --devtool source-map --config webpack.config.js

I have provided the Firebase setup calls in my issue post.

I think it might be difficult for you to reproduce the issue, as we have not been able to either. An unpredictable subset of our users gets the issue each time. In my issue post, I have provided the relevant code lines where the issue is seen in production, based on the logging we added. I have also provided the patch file we used for the logging. We are happy to provide you more info by adding more logging as might be useful for you based on the code shown so far.

@GaurangTandon
Copy link
Author

After adding more logs to the Firebase Auth package, I have found the code hangs at exactly at this call: this.stsTokenManager.getToken(this.auth, forceRefresh)) (here forceRefresh is undefined).

I have attached the updated patch file. @firebase+auth+1.7.1.patch

Here is the full stack trace (top to bottom) for your reference:

// _initializeWithPersistence
// initializeCurrentUser with popupRedirectResolver as falsy
...
            if (futureCurrentUser) {
                tbLog('ICU: c1'); // <-- this got printed
                return this.reloadAndSetCurrentUserOrClear(futureCurrentUser); // <-- hang inside this
            }
...
    async reloadAndSetCurrentUserOrClear(user) {
        try {
            tbLog('RSC: 1'); // <-- this got printed
            await _reloadWithoutSaving(user); // <-- hang inside this
        }
...
async function _reloadWithoutSaving(user) {
    var _a;
    const auth = user.auth;
    tbLog('RWS: 1'); // <-- this got printed
    const idToken = await user.getIdToken(); // <-- hang inside this
    tbLog('RWS: 2'); // <-- this was not printed
...
    async getIdToken(forceRefresh) {
        tbLog('GIT: 0'); // <-- this got printed
        const accessToken = await _logoutIfInvalidated(this, this.stsTokenManager.getToken(this.auth, forceRefresh)); // <-- hang inside this
        tbLog('GIT: 1'); // <-- this was not printed
...
async function _logoutIfInvalidated(user, promise, bypassAuthState = false) {
    tbLog('LIF: 0 ' + !!bypassAuthState);
    if (bypassAuthState) {
        return promise;
    }
    try {
        tbLog('LIF: 1'); // <-- this got printed
        return await promise; // <-- hanged here
    }

I hope these logs are enough information to diagnose what the issue is, and if you need more logs, please let me know.

@GaurangTandon
Copy link
Author

GaurangTandon commented Sep 12, 2024

Update: I found (from another log) that it can also hang on getAccountInfo(auth, { idToken }) call. Continuing from above stack trace:

async function _reloadWithoutSaving(user) {
    var _a;
    const auth = user.auth;
    tbLog('RWS: 1'); // <-- this got printed
    const idToken = await user.getIdToken();
    tbLog('RWS: 2'); // <-- this was also printed
    const response = await _logoutIfInvalidated(user, getAccountInfo(auth, { idToken })); // <-- hang inside this    
...
async function _logoutIfInvalidated(user, promise, bypassAuthState = false) {
    tbLog('LIF: 0 ' + !!bypassAuthState);
    if (bypassAuthState) {
        return promise;
    }
    try {
        tbLog('LIF: 1'); // <-- this got printed
        return await promise; // <-- hanged here
    }

Looks like getAccountInfo is doing a POST request which can either hang on the network itself or at steps such as the heartbeatsHeader step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants