Firebase signInWithRedirect not working? Fix it by cause

Updated 26 Oct 2026 · Pewterkit Guides

If Google sign-in with signInWithRedirect sends users to Google and back but they arrive signed out, the most common cause is that your app is not served from the same domain as your authDomain, and the browser now partitions the storage the Firebase helper needs. Fix it by applying one of Firebase's five documented options; then check the getRedirectResult and listener-timing causes below.

Why signInWithRedirect stops working

The redirect flow has three legs:

  1. Your page calls signInWithRedirect(auth, provider). In the current SDK source, it writes a small "pending redirect" flag to sessionStorage on your origin, then sends the browser to https://<authDomain>/__/auth/handler.
  2. The handler page on your authDomain (by default <project>.firebaseapp.com) sends the user to Google, receives the response, and stores the outcome in its own storage.
  3. The browser returns to your page. The SDK loads a hidden iframe from https://<authDomain>/__/auth/iframe to read that outcome.

Step 3 is the one that breaks. Firebase's guide says the SDK "uses a cross-origin iframe that connects to your app's Firebase Hosting domain" and that "this mechanism doesn't work with browsers that block third-party storage access." Chrome has partitioned third-party storage for all users since Chrome 115: an iframe from firebaseapp.com embedded in yourapp.com gets a separate storage bucket, so it cannot see what the handler stored when it was the top-level page. Firefox does the same by default since Firefox 103.

Firebase's own note (checked Oct 2026): one of the options is required for redirect sign-in "on Google Chrome M115+" starting June 24, 2024, and "already required on Firefox 109+ and Safari 16.1+."

The result looks like this: no error in your code, getRedirectResult resolves to null, onAuthStateChanged reports null, and in some cases the user sees "Unable to process request due to missing initial state." That last message has its own page: missing initial state explained.

Step 1: pick the fix that matches your hosting

Firebase decides which option applies by where your app is served:

Where the app is served What to do
Firebase Hosting on <project>.firebaseapp.com Not affected. No change needed.
Firebase Hosting on a custom domain or <project>.web.app Option 1
Any other host (Vercel, Netlify, Cloudflare, Cloud Run, your own server) Option 2, 3, 4 or 5

Option 1: use your Firebase Hosting custom domain as authDomain

Only for apps on Firebase Hosting, with the custom domain connected to the same project you use for Auth.

const firebaseConfig = {
  apiKey: "<api-key>",
  authDomain: "app.example.com", // the domain that serves your app
  projectId: "<project-id>",
  appId: "<app-id>",
};

Then:

  1. In the Google Cloud console, open the Clients page under Google Auth Platform (older guides: APIs & Services > Credentials; labels as of Oct 2026), open the Web client your Firebase project uses, and add https://app.example.com/__/auth/handler to Authorized redirect URIs. The /__/auth/handler suffix matters.
  2. Make sure app.example.com is in Firebase's authorized domains list (Firebase console > Security > Authentication > Settings > Authorized domains as of Oct 2026; older guides say Build > Authentication > Settings).
  3. Redeploy with Firebase Hosting so /__/firebase/init.json is current.

If the redirect URI step is skipped, Google answers with redirect_uri_mismatch. That error has its own walkthrough: redirect_uri_mismatch.

Option 2: switch to signInWithPopup

The smallest code change. Firebase lists it as a valid fix:

import { signInWithPopup, GoogleAuthProvider } from "firebase/auth";

// Before: signInWithRedirect(auth, provider) + getRedirectResult(auth)
const userCred = await signInWithPopup(auth, new GoogleAuthProvider());

Firebase's caveat: popups are "occasionally blocked by the device or platform, and the flow is less smooth for mobile users." For the trade-offs, see popup or redirect.

Option 3: reverse-proxy /__/auth through your own domain

Keeps the redirect flow on a non-Firebase server you control. Forward GET and POST requests for https://<your domain>/__/auth/ to https://<project>.firebaseapp.com/__/auth/. Firebase is explicit that this must be transparent to the browser: "this cannot be done via a 302 Redirect."

nginx, from Firebase's guide:

# reverse proxy for signin-helpers for popup/redirect sign in.
location /__/auth {
  proxy_pass https://<project>.firebaseapp.com;
}

Then do the Option 1 steps: set authDomain to your app's domain, add https://<your domain>/__/auth/handler to the OAuth client's redirect URIs, and redeploy.

Test this on a preview deployment before relying on it.

Option 4: self-host the helper files

Only if a proxy is not possible. Download these from https://<project>.firebaseapp.com and serve them at the same paths on your domain: /__/auth/handler, /__/auth/handler.js, /__/auth/experiments.js, /__/auth/iframe, /__/auth/iframe.js, /__/auth/links, /__/auth/links.js, /__/firebase/init.json. Firebase notes this does not work for Apple sign-in or SAML, and recommends re-syncing the files periodically. Then do the Option 1 steps.

Option 5: sign in with Google yourself, then hand the token to Firebase

Use Google's own sign-in library to get an ID token, then exchange it:

import { GoogleAuthProvider, signInWithCredential } from "firebase/auth";

// idToken comes from the Sign In With Google callback (response.credential)
const credential = GoogleAuthProvider.credential(idToken);
await signInWithCredential(auth, credential);

Firebase calls this "a complex approach that uses additional SDKs."

Step 2: if getRedirectResult still returns null

getRedirectResult returns null whenever "no redirect operation was called," so null on a normal page load is expected. It is a bug only right after a sign-in round trip. Check these in order:

  1. You called it twice. In the current SDK source, the redirect outcome goes to the first getRedirectResult call of the page load, and later calls get null. React StrictMode running effects twice in development is a common source. Call it once, outside components; the pattern is in signInWithRedirect in React.
  2. You came back to a different origin. The pending-redirect flag lives in sessionStorage, which MDN describes as scoped to the origin and the tab. Starting on https://example.com and landing on https://www.example.com (or http:// vs https://, or another port) means the flag is not there. Redirect once at the edge so users start sign-in on the same origin they return to.
  3. The page you return to has a different config. In the current SDK source, a pending redirect is processed at start-up only when authDomain is set, so the config on the return page needs the same authDomain (and API key) as the page that started sign-in.
  4. You used initializeAuth without a resolver. getAuth() includes the browser popup/redirect resolver; initializeAuth() does not unless you pass it:
import { initializeAuth, browserLocalPersistence, browserPopupRedirectResolver } from "firebase/auth";

const auth = initializeAuth(app, {
  persistence: browserLocalPersistence,
  popupRedirectResolver: browserPopupRedirectResolver,
});
  1. It only fails on localhost. Your dev origin is not your authDomain, so Step 1 applies there too. See signInWithRedirect on localhost.

Step 3: read the user from the auth state listener

Do not decide "signed in or not" from auth.currentUser right after load. Firebase's docs say currentUser "might also be null because the auth object has not finished initializing," and that when you use signInWithRedirect, "the onAuthStateChanged observer waits until getRedirectResult resolves before triggering." So:

import { onAuthStateChanged, getRedirectResult } from "firebase/auth";

// Who is signed in: always from the listener (or after authStateReady()).
onAuthStateChanged(auth, (user) => {
  render(user); // null = signed out, after any redirect has been processed
});

// Only for the provider credential, errors, or first-sign-in info:
getRedirectResult(auth)
  .then((result) => {
    if (result) console.log("redirect sign-in:", result.operationType);
  })
  .catch((error) => showError(error.code));

If you need a one-off check before routing, await auth.authStateReady() resolves when the initial auth state is settled.

On mobile

The causes and fixes above are the same on phones. Firebase's Google sign-in guide says "the redirect method is preferred on mobile devices," so mobile builds are often the ones using redirect, and Firebase's note lists Safari 16.1+ among the browsers that need one of the options. One extra check: sessionStorage is scoped to a tab, so if the round trip ends in a different tab or browser than it started in, the pending flag may be missing and the result null.

How to confirm it worked

  1. Open DevTools > Network and click your sign-in button. The first navigation should go to https://<your authDomain>/__/auth/handler with a 200. After Option 1, 3 or 4, that host is your own domain.
  2. Optional: DevTools > Application > Session storage for your origin may briefly show a key starting with firebase:pendingRedirect: while the redirect is in progress. This is an SDK internal detail that can change, and the SDK removes the key once it processes the return.
  3. After you return, getRedirectResult resolves once with a result whose operationType is "signIn", and onAuthStateChanged fires with a user.
  4. Repeat in a private window in Chrome and Firefox. No "missing initial state" message should appear.

FAQ

Why did signInWithRedirect work before and stop without any code change?

Browsers changed, not your code. Firebase states that from June 24, 2024 Chrome M115+ needs one of its five options for redirect sign-in, and that Firefox 109+ and Safari 16.1+ already did.

Is getRedirectResult returning null always an error?

No. It returns null when no redirect sign-in is pending, which is every normal page load, and, in the current SDK, on a second call in the same page load. Treat it as an error only right after the user comes back from Google.

Do I need to change anything if I host on Firebase Hosting?

Not on <project>.firebaseapp.com. On a custom domain or <project>.web.app, set authDomain to the domain that serves the app and add its /__/auth/handler URL to your OAuth client (Option 1).

Can I fix this without a proxy?

Yes: switch to signInWithPopup (Option 2), self-host the helper files (Option 4), or use Google's sign-in library with signInWithCredential (Option 5).

Sources

  1. Best practices for using signInWithRedirect on browsers that block third-party storage access
  2. Authenticate Using Google with JavaScript
  3. Manage Users in Firebase
  4. firebase/auth module reference (getRedirectResult, signInWithRedirect, initializeAuth)
  5. Auth interface reference (authStateReady)
  6. Storage Partitioning (Chrome for Developers)
  7. State Partitioning (MDN)
  8. Window: sessionStorage property (MDN)
  9. firebase-js-sdk source: core/strategies/redirect.ts
  10. firebase-js-sdk source: core/auth/auth_impl.ts
  11. firebase-js-sdk source: core/util/handler.ts
  12. firebase-js-sdk issue #8467: "Unable to process request due to missing initial state"

How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked 26 Oct 2026. Spotted something out of date? Tell us.

Related guides