Firebase sign-in fails in Firefox and Safari: "missing initial state" and blocked popups
Firefox and Safari give each site its own separate storage for embedded third-party content, so when your app and your Firebase authDomain are on different sites, the sign-in helper cannot read the state it saved and shows "missing initial state." Fix it with one of Firebase's five options (same-domain authDomain, popup, reverse proxy, self-hosted helper, or your own Google sign-in), and open popups straight from the click so Safari does not block them.
What each browser does to the Firebase sign-in helper
Firebase's redirect flow loads helper code from your authDomain (<project>.firebaseapp.com by default) in a cross-origin iframe. When the user comes back, that helper needs to read storage it wrote earlier. Firebase states the mechanism "doesn't work with browsers that block third-party storage access." If the browser hands the helper a different, partitioned storage bucket, the handler reports: "Unable to process request due to missing initial state. This may happen if browser sessionStorage is inaccessible or accidentally cleared."
| Browser | Firebase says a fix is required from | What the browser does (vendor docs) |
|---|---|---|
| Firefox | Firefox 109+ | Total Cookie Protection maintains "a separate cookie jar for each website" and is on by default in standard browsing. Under State Partitioning, Firefox double-keys client-side state, including localStorage, sessionStorage and IndexedDB, by the resource's origin and the top-level site. MDN says State Partitioning has been on by default since Firefox 103. |
| Safari | Safari 16.1+ | WebKit's tracking prevention "by default blocks all third-party cookies," and third-party LocalStorage and IndexedDB "are partitioned per first-party website and also made ephemeral." |
| Chrome | Chrome M115+, required from June 24, 2024 | Storage partitioning (localStorage, sessionStorage, IndexedDB and others) is enabled for all users on Chrome 115 and later. Google said in 2025 that Chrome keeps its current approach of letting users choose about third-party cookies. |
So this is not a Firefox or Safari bug to wait out. All three browsers isolate the helper's storage; the fix belongs in your app's setup.
Step 1: Confirm it's a storage-partitioning problem
- Compare two hostnames: the one in your address bar and the
authDomainin your Firebase config. If they are different sites (for exampleapp.example.comandmy-project.firebaseapp.com), you are affected. Firebase says apps served from their ownfirebaseapp.comsubdomain on Firebase Hosting are not affected. - Open DevTools > Network, start sign-in, and look at the
/__/auth/iframeand/__/auth/handlerrequests. If their host differs from your app's site, the helper is running as a third party. - Reproduce in a Firefox private window and in Safari. If sign-in also fails the same way on
firebaseapp.comitself, the cause is elsewhere; see signInWithRedirect not working.
Don't ask users to switch off tracking protection. Firebase says asking users to disable storage partitioning "is rarely an option," and MDN warns that Firefox's temporary storage-access heuristics, which can make the flow work for some users some of the time, "should not be relied upon."
Step 2: Apply one of Firebase's five fixes
| Your setup | Use |
|---|---|
Firebase Hosting on a custom domain or web.app |
Option 1 |
| Any other host, popups acceptable | Option 2 |
| Any other host, you control routing or a proxy | Option 3 |
| Proxy not possible, Google sign-in only | Option 4 |
| You want to drop Firebase's popup/redirect helpers entirely | Option 5 |
Option 1: Use your Firebase Hosting domain as authDomain
Change only authDomain; Firebase says not to modify other config fields.
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: "<api-key>",
authDomain: "app.example.com", // the domain that serves your app
projectId: "<project-id>",
appId: "<app-id>",
};
export const app = initializeApp(firebaseConfig);
Then (console steps as of Oct 2026):
- Add
https://app.example.com/__/auth/handlerto your Google OAuth client's Authorized redirect URIs. The trailing/__/auth/handleris required. - Make sure the domain is listed under Security > Authentication > Settings > Authorized domains in the Firebase console (older guides: Build > Authentication > Settings).
- Redeploy on Firebase Hosting so
/__/firebase/init.jsonis current.
Option 2: Switch to signInWithPopup
import { getAuth, GoogleAuthProvider, signInWithPopup } from "firebase/auth";
const auth = getAuth(app);
const userCred = await signInWithPopup(auth, new GoogleAuthProvider());
Remove the getRedirectResult step. Firebase notes popups can be blocked and are less smooth on mobile; see the Safari section below.
Option 3: Reverse-proxy /__/auth/ to firebaseapp.com
Forward GET and POST requests for https://app.example.com/__/auth/ to https://<project>.firebaseapp.com/__/auth/. It must be transparent to the browser; a 302 redirect will not work. Firebase's nginx example:
# reverse proxy for signin-helpers for popup/redirect sign in.
location /__/auth {
proxy_pass https://<project>.firebaseapp.com;
}
Then do the three Option 1 steps (authDomain, redirect URI, authorized domain). Platform-specific proxy setups are in How to change your Firebase authDomain.
Option 4: Self-host the sign-in helper files
Download these from <project>.firebaseapp.com and serve them from your domain at the same paths: __/auth/handler, __/auth/handler.js, __/auth/experiments.js, __/auth/iframe, __/auth/iframe.js, __/auth/links, __/auth/links.js and __/firebase/init.json. Re-sync them periodically to pick up fixes, then do the Option 1 steps. Firebase says this option does not work for Apple sign-in or SAML.
Option 5: Sign in with Google yourself, then hand the credential to Firebase
Firebase's own Option 5 sample uses the older gapi.auth2 library. The same idea with the Google Identity Services library looks like this:
<script src="https://accounts.google.com/gsi/client" async></script>
<div id="google-btn"></div>
import { getAuth, GoogleAuthProvider, signInWithCredential } from "firebase/auth";
const auth = getAuth(app);
window.onload = () => {
google.accounts.id.initialize({
client_id: "<your-web-client-id>.apps.googleusercontent.com",
callback: async (response) => {
// response.credential is the Google ID token (a JWT)
const credential = GoogleAuthProvider.credential(response.credential);
await signInWithCredential(auth, credential);
},
});
google.accounts.id.renderButton(document.getElementById("google-btn"), {
theme: "outline",
size: "large",
});
};
Add your site (scheme and hostname only) to that client's Authorized JavaScript origins; for local work add both http://localhost and http://localhost:<port>.
Test this on a preview deployment before relying on it.
Safari says auth/popup-blocked
If you chose Option 2 and Safari users get auth/popup-blocked, a common cause is a popup opened outside a direct user gesture. MDN: popups "must be opened in direct response to user input," and that permission (transient activation) expires and is consumed by window.open(). Safari also has a user-level Block Pop-ups setting.
Fix it in code first:
- Import and initialize
firebase/authwhen the page loads, not inside the click handler. - Make
signInWithPopupthe first awaited call in the click handler. Nofetch, dynamicimport()or otherawaitbefore it. - Fall back to a redirect only once Option 1, 3 or 4 is in place, or the redirect will hit "missing initial state" instead.
import { getAuth, GoogleAuthProvider, signInWithPopup, signInWithRedirect } from "firebase/auth";
const auth = getAuth(app);
const provider = new GoogleAuthProvider();
document.getElementById("google-signin").addEventListener("click", async () => {
try {
await signInWithPopup(auth, provider); // first await in the handler
} catch (err) {
if (err.code === "auth/popup-blocked") {
await signInWithRedirect(auth, provider); // needs Option 1, 3 or 4
} else {
throw err;
}
}
});
If a user has blocked pop-ups themselves, Apple documents the switches: on iPhone or iPad, Settings > Apps > Safari > Block Pop-ups; on Mac, Safari > Settings > Websites > Pop-up Windows, then choose Allow for your site. Mozilla says Firefox blocks pop-ups by default, but events such as a click or key press can still open them; users can add an exception from Settings > Privacy & Security, using the Exceptions button next to the pop-up blocking option in the Permissions section. More on this error: auth/popup-blocked.
How to confirm it worked
- In a Firefox private window and in Safari, complete a redirect sign-in.
getRedirectResult(auth)should return a user, andauth.currentUsershould be set after reload. - With Options 1, 3 or 4, DevTools > Network should show
/__/auth/handleron your own domain. - With Option 2, click the button once in Safari: the Google window should open with no blocked-popup icon in the address bar.
Related problems
- Choosing between the two flows: Popup or redirect?
- What the error text means in plain terms: Missing initial state, explained
FAQ
Can I just tell users to turn off Enhanced Tracking Protection?
You shouldn't need to. Firebase says asking users to disable storage partitioning "is rarely an option," so fix the setup so sign-in works with protections on.
Is Chrome affected too?
Yes. Firebase says one of the options is required for redirect sign-in on Chrome M115+ from June 24, 2024, and Chrome partitions sessionStorage and other storage for all users from Chrome 115.
Does signInWithPopup avoid the storage problem?
Firebase lists switching to signInWithPopup() as Option 2 for browsers that block third-party storage. The trade-off is that popups can be blocked and work less smoothly on mobile.
Which option works for Apple sign-in?
Firebase says Option 4 (self-hosting the helper files) does not work for Apple sign-in or SAML, and recommends it only when a reverse proxy (Option 3) isn't feasible. Use Option 1, 2 or 3 instead.
Sources
- Best practices for using signInWithRedirect on browsers that block third-party storage access (Firebase)
- Firebase JS SDK auth reference: signInWithPopup, signInWithRedirect, AuthErrorCodes
- Authenticate with Firebase using email link: authorized domains (Firebase)
- firebase-android-sdk issue #7379 (full error text) (GitHub)
- MDN: State Partitioning
- Mozilla Support: Total Cookie Protection
- Mozilla Support: Pop-up blocker settings, exceptions and troubleshooting
- WebKit: Tracking Prevention in WebKit
- Privacy Sandbox: Storage Partitioning (Chrome)
- Privacy Sandbox: Next steps for Privacy Sandbox and tracking protections in Chrome (Apr 2025)
- Privacy Sandbox: Update on plans for Privacy Sandbox technologies (Oct 2025)
- MDN: User activation
- MDN: Window.open()
- Apple Support: Block pop-up ads and windows in Safari
- Apple Support: Allow or block pop-ups in Safari on Mac
- Google Identity Services: JavaScript API reference
- Google Identity Services: Load the client library
- Google Identity Services: Get your Google API client ID
How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked Oct 27, 2026. Spotted something out of date? Tell us.