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
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 usingindexedDBLocalPersistence
. Therefore, the observations I made below are only partially correct. ChangingbrowserLocalPersistence
toindexedDBLocalPersistence
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
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
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)
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.
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.
Secondly use onAuthStateChanged listener to manage the user state across tabs:
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: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.