Firebase sign-in fails in Firefox and Safari: "missing initial state" and blocked popups

Updated Oct 27, 2026 · Pewterkit Guides

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

  1. Compare two hostnames: the one in your address bar and the authDomain in your Firebase config. If they are different sites (for example app.example.com and my-project.firebaseapp.com), you are affected. Firebase says apps served from their own firebaseapp.com subdomain on Firebase Hosting are not affected.
  2. Open DevTools > Network, start sign-in, and look at the /__/auth/iframe and /__/auth/handler requests. If their host differs from your app's site, the helper is running as a third party.
  3. Reproduce in a Firefox private window and in Safari. If sign-in also fails the same way on firebaseapp.com itself, 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):

  1. Add https://app.example.com/__/auth/handler to your Google OAuth client's Authorized redirect URIs. The trailing /__/auth/handler is required.
  2. Make sure the domain is listed under Security > Authentication > Settings > Authorized domains in the Firebase console (older guides: Build > Authentication > Settings).
  3. Redeploy on Firebase Hosting so /__/firebase/init.json is 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:

  1. Import and initialize firebase/auth when the page loads, not inside the click handler.
  2. Make signInWithPopup the first awaited call in the click handler. No fetch, dynamic import() or other await before it.
  3. 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, and auth.currentUser should be set after reload.
  • With Options 1, 3 or 4, DevTools > Network should show /__/auth/handler on 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.

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

  1. Best practices for using signInWithRedirect on browsers that block third-party storage access (Firebase)
  2. Firebase JS SDK auth reference: signInWithPopup, signInWithRedirect, AuthErrorCodes
  3. Authenticate with Firebase using email link: authorized domains (Firebase)
  4. firebase-android-sdk issue #7379 (full error text) (GitHub)
  5. MDN: State Partitioning
  6. Mozilla Support: Total Cookie Protection
  7. Mozilla Support: Pop-up blocker settings, exceptions and troubleshooting
  8. WebKit: Tracking Prevention in WebKit
  9. Privacy Sandbox: Storage Partitioning (Chrome)
  10. Privacy Sandbox: Next steps for Privacy Sandbox and tracking protections in Chrome (Apr 2025)
  11. Privacy Sandbox: Update on plans for Privacy Sandbox technologies (Oct 2025)
  12. MDN: User activation
  13. MDN: Window.open()
  14. Apple Support: Block pop-up ads and windows in Safari
  15. Apple Support: Allow or block pop-ups in Safari on Mac
  16. Google Identity Services: JavaScript API reference
  17. Google Identity Services: Load the client library
  18. 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.

Related guides