Firebase signInWithRedirect not working? Fix it by cause
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:
- Your page calls
signInWithRedirect(auth, provider). In the current SDK source, it writes a small "pending redirect" flag tosessionStorageon your origin, then sends the browser tohttps://<authDomain>/__/auth/handler. - 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. - The browser returns to your page. The SDK loads a hidden iframe from
https://<authDomain>/__/auth/iframeto 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:
- 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/handlerto Authorized redirect URIs. The/__/auth/handlersuffix matters. - Make sure
app.example.comis in Firebase's authorized domains list (Firebase console > Security > Authentication > Settings > Authorized domains as of Oct 2026; older guides say Build > Authentication > Settings). - Redeploy with Firebase Hosting so
/__/firebase/init.jsonis 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:
- You called it twice. In the current SDK source, the redirect outcome goes to the first
getRedirectResultcall of the page load, and later calls getnull. React StrictMode running effects twice in development is a common source. Call it once, outside components; the pattern is in signInWithRedirect in React. - 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 onhttps://example.comand landing onhttps://www.example.com(orhttp://vshttps://, 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. - The page you return to has a different config. In the current SDK source, a pending redirect is processed at start-up only when
authDomainis set, so the config on the return page needs the sameauthDomain(and API key) as the page that started sign-in. - You used
initializeAuthwithout 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,
});
- 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
- Open DevTools > Network and click your sign-in button. The first navigation should go to
https://<your authDomain>/__/auth/handlerwith a200. After Option 1, 3 or 4, that host is your own domain. - 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. - After you return,
getRedirectResultresolves once with a result whoseoperationTypeis"signIn", andonAuthStateChangedfires with a user. - Repeat in a private window in Chrome and Firefox. No "missing initial state" message should appear.
Related problems
redirect_uri_mismatchafter changingauthDomain: the handler URL on your domain is not in the OAuth client. See redirect_uri_mismatch after changing authDomain.auth/unauthorized-domain: the domain the app runs on is not in Firebase's authorized domains list. See Firebase authorized domains.- React or Vite apps that sign in and then bounce back to the login page: usually a router guard deciding before auth state settles. See signInWithRedirect in React.
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
- Best practices for using signInWithRedirect on browsers that block third-party storage access
- Authenticate Using Google with JavaScript
- Manage Users in Firebase
- firebase/auth module reference (getRedirectResult, signInWithRedirect, initializeAuth)
- Auth interface reference (authStateReady)
- Storage Partitioning (Chrome for Developers)
- State Partitioning (MDN)
- Window: sessionStorage property (MDN)
- firebase-js-sdk source: core/strategies/redirect.ts
- firebase-js-sdk source: core/auth/auth_impl.ts
- firebase-js-sdk source: core/util/handler.ts
- 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.