skip to Main Content

I am using Firebase Authentication in my project and everything works fine but I have a contextmenu on several objects in my app which opens a new tab (within the same app).

When the user opens a new tab for the first time in this session the first/initial tab loses his auth state and therefore all subscribers unsubscribe (because of missing permissions) and the user sees the login page in that tab.

My login function (and persistence settings) looks like this.

const login = async (values: { email: string; password: string }) => {
        try {
            // some unrelated code above
            const { email, password } = values;
            await setPersistence(auth, browserLocalPersistence);
            await signInWithEmailAndPassword(auth, email, password);
        } catch (error) {
            console.error(error);
        } finally {
            // some more unrelated code below
        }
    };

When the user keeps on using the app in one of the newer tabs and for example triggers a new tab from there the auth state works fine. It only happens on the very first (initial) tab.

Am I doing something wrong with my login process or is this a common issue from firebase?
I searched the web and unfortunately couldn’t find someone with the same issue.

Thanks in advance.

Update:

I moved the

await setPersistence(auth, browserLocalPersistence);

in the onAuthStateChanged Listener and it looks like it solves my problem (for the moment).

Update (25th April 2023):

Unfortunately it is still not working as expected.. Is there any solution for that or a hint what I am doing wrong? I would really appreciate some help here.

Also this behavior only appears when opening the new tab with window.open('/foo', '_blank'). When I am opening the desired target URL manually by copy&paste the auth state won’t change on the initial tab.

2

Answers


  1. Edit (28.04.2023):

    I had assumed that the default persistence local was handled using browserLocalPersistence, but my later experiments showed that it is actually handled using indexedDBLocalPersistence. Therefore, the observations I made below are only partially correct. Changing browserLocalPersistence to indexedDBLocalPersistence for the first two cases will also fix your problem.

    In conclusion, it seems that using localStorage to store the authentication token is not sufficient for persisting authentication across browser tabs (at least for the first tab). However, using indexedDB is.

    Original Answer

    First of all, Overview of persistence behavior#2 in Firebase Authentication State Persistence Documentation says

    • If no user is signed in and no persistence is specified, the default setting will be applied (local in a browser app)

    since your persistence requirement is also local, you don’t need to specify any persistence.

    To understand your problem clearly, I’ve created a basic Next.js + Firebase authentication app and have tested it (demo) with and without the code-line

    await setPersistence(auth, browserLocalPersistence);
    

    These are my observations:

    1. Using setPersistence function for every login (login.tsx) or onAuthStateChange event. I observe similar problem that you mention in your question.

    2. Using setPersistence function only once right after initializing auth. (firebaseClient.js)

    const auth = getAuth(app);
    setPersistence(auth, browserLocalPersistence);
    
    export { auth }
    

    Fixes your problem but causes another issuse (I may have miss/wrong used setPersistence) for following use case;

    Open app > Go to login page > Login > Open authenticated page in new tab > Logout from that tab > Back to previous tab > Go back to home page > Expect that you are not logged in but actually you look logged in until you refresh the page.

    3. Remove setPersistence function from everywhere, leave firebase to use the default persistence (which is local as I mentioned before). Fixes the problem that you have and no side-effects occurs.

    If I correctly understand your problem, this should fix it. But if not, please check Expected behavior across browser tabs and also make sure that your auth context and authentication logic is similar to the example app (which I create it by following a blog post Authenticated server-side rendering with Next.js and Firebase) that I mentioned.

    Login or Signup to reply.
  2. Based on your description, it appears that the issue is related to the auth state being lost when a new tab is opened within the same app. This could be due to the way the authentication persistence is being set.

    When you set the persistence to browserLocalPersistence, it stores the authentication state in the browser’s local storage. However, it might not be immediately available when a new tab is opened, causing the initial tab to lose its auth state.

    To resolve this issue, you can try the following:
    First, set the persistence outside the login function, ideally at the beginning of your app’s initialization.

    import { initializeApp } from "firebase/app";
    import { getAuth, browserLocalPersistence, setPersistence } from "firebase/auth";
    
    const firebaseApp = initializeApp(/* your firebase config */);
    const auth = getAuth(firebaseApp);
    
    // Set persistence here
    (async () => {
      try {
        await setPersistence(auth, browserLocalPersistence);
      } catch (error) {
        console.error("Failed to set persistence:", error);
      }
    })();
     
    

    Secondly use onAuthStateChanged listener to manage the user state across tabs:

    import { onAuthStateChanged } from "firebase/auth";
    
    onAuthStateChanged(auth, (user) => {
      if (user) {
        // The user is signed in, update the app state accordingly
      } else {
        // The user is signed out or the state changed, update the app state accordingly
      }
    });
    

    By setting the persistence outside the login function and using the onAuthStateChanged listener, you ensure that the auth state is managed consistently across all tabs in your app.

    If the issue still persists, consider using indexedDB as the storage option for authentication persistence:

    import { indexedDBLocalPersistence } from "firebase/auth";
    
    await setPersistence(auth, indexedDBLocalPersistence);
    

    This can help improve the synchronization of the auth state between tabs. However, be aware that indexedDB has different browser support and performance characteristics compared to local storage.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search