Firebase Auth on Netlify: fix auth/unauthorized-domain on Deploy Previews and branch deploys
Firebase sign-in fails on Netlify Deploy Previews with auth/unauthorized-domain because each pull request, and each individual deploy, gets its own --<site>.netlify.app hostname that isn't on Firebase's Authorized domains list.
Authorize your production hosts plus a branch deploy you test sign-in on (such as staging--<site>.netlify.app), and on production proxy /__/auth/* with a _redirects or netlify.toml rule placed above your SPA catch-all.
Why Netlify deploys trip Firebase's domain check
Firebase's SDK throws auth/unauthorized-domain with the message "This domain is not authorized for OAuth operations for your Firebase project. Edit the list of authorized domains from the Firebase console." Firebase's help page says you must whitelist "the full domain names" of your web app's hosts.
Netlify publishes the same site at several kinds of hostname:
| Netlify deploy | Hostname | How long it stays the same |
|---|---|---|
| Production | <site>.netlify.app and your custom domain |
Permanent |
| Deploy Preview (pull request) | deploy-preview-<PR number>--<site>.netlify.app |
For that pull request; a new PR gets a new hostname |
| Deploy permalink | <deploy-id>--<site>.netlify.app |
A new one for every deploy |
| Branch deploy | <branch>--<site>.netlify.app, e.g. staging--<site>.netlify.app |
As long as the branch exists |
| Agent run preview | agent-<run-id>--<site>.netlify.app |
For that run |
Two details catch people out:
- A Deploy Preview URL is stable while its pull request is open, but every new PR changes the number, so the host you authorized last week no longer matches.
- Branch deploys are off by default: "Netlify will not generate a branch deploy unless a Developer or Owner has set up branch deploys for your site."
Firebase's list takes full domain names; for what wildcard entries can and can't do, see Firebase authorized domains and wildcards.
Fix step by step
1. Turn on a branch deploy for sign-in testing
As of Oct 2026, Netlify's steps: Project configuration > Developer settings > Continuous deployment > Branches and deploy contexts, select Configure, choose Let me add individual branches, enter staging (or your review branch), and Save. Pushes to that branch then deploy to staging--<site>.netlify.app, a hostname that doesn't change.
2. Add the stable hosts to Firebase's Authorized domains
As of Oct 2026, Firebase's docs give the path Security > Authentication > Settings tab > Authorized domains > Add domain; older guides and menus show Build > Authentication > Settings. Enter hostnames only:
www.example.com
<site>.netlify.app
staging--<site>.netlify.app
The full background on this list is in Firebase authorized domains.
3. Need sign-in on one specific pull request?
Add that PR's host, for example deploy-preview-42--<site>.netlify.app, while the PR is open, and remove it after merging, so PR hosts don't pile up on the list.
4. (Optional) Branded deploy hostnames with Netlify DNS
If your domain is managed by Netlify DNS, Netlify can serve branch deploys at a custom branch subdomain such as staging.example.com, and Deploy Previews or branch deploys at an automatic deploy subdomain (for example deploy-preview-42.preview.example.com if your deploy subdomain is preview.example.com). Branch subdomains give you one stable host to authorize. Deploy Previews still get one hostname per pull request, so they still need step 3.
Production on Netlify: proxy /__/auth/* and set authDomain per context
If production uses signInWithRedirect, Firebase's redirect best-practices page says one of its options is "required for redirect sign-in to work on Google Chrome M115+" and "already required on Firefox 109+ and Safari 16.1+". For apps hosted outside Firebase, those options include signInWithPopup() (Option 2) or forwarding /__/auth/ on your domain to https://<project>.firebaseapp.com/__/auth/ (Option 3). On Netlify, Option 3 is a proxy rewrite: "When you assign an HTTP status code of 200 to a redirect rule, it becomes a rewrite", so the visitor's URL stays the same, as Firebase requires ("this cannot be done via a 302 Redirect").
Option A: _redirects file. It must end up in your publish directory. With Vite, put it in public/, which Vite copies "to the root of the dist directory as-is":
# public/_redirects
/__/auth/* https://<project-id>.firebaseapp.com/__/auth/:splat 200
/* /index.html 200
Netlify "will process the first matching rule it finds, reading from top to bottom", so the /__/auth/* line has to sit above the single-page-app catch-all, or the catch-all serves your index.html for Firebase's handler.
Option B: netlify.toml.
[[redirects]]
from = "/__/auth/*"
to = "https://<project-id>.firebaseapp.com/__/auth/:splat"
status = 200
force = true
Watch the order across files: "Rules in the _redirects file are always processed first, followed by rules in the Netlify configuration file." If a /* /index.html 200 catch-all lives in _redirects, it matches before this netlify.toml rule. Keep both rules in the same file, auth rule first.
Firebase asks for GET and POST requests to /__/auth/ to be forwarded. Test this on a preview deployment before relying on it.
Next.js on Netlify: Netlify's Next.js docs list redirects and rewrites as fully supported, so you can use a next.config.js rewrite instead; see Next.js + Firebase Google sign-in.
Set authDomain per deploy context
Your custom authDomain only works on the host whose /__/auth/handler URI is registered on the Google OAuth client, so give previews and branch deploys the default. The production context also builds what <site>.netlify.app serves, so send redirect sign-in users to your custom domain rather than the netlify.app address. Netlify deploy contexts make this a build setting:
# netlify.toml
[context.production.environment]
VITE_FIREBASE_AUTH_DOMAIN = "www.example.com"
[context.deploy-preview.environment]
VITE_FIREBASE_AUTH_DOMAIN = "<project-id>.firebaseapp.com"
[context.branch-deploy.environment]
VITE_FIREBASE_AUTH_DOMAIN = "<project-id>.firebaseapp.com"
// firebase.js (Vite exposes VITE_-prefixed variables to client code)
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const app = initializeApp({
apiKey: "<api-key>",
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: "<project-id>",
appId: "<app-id>",
});
export const auth = getAuth(app);
Then, on the Google OAuth web client, add https://www.example.com/__/auth/handler to Authorized redirect URIs ("the trailing /__/auth/handler is important"). The full sequence is in change Firebase authDomain. Netlify also notes that "Paths handled by proxies or functions may not redirect from HTTP to HTTPS URLs as expected" and recommends publishing only HTTPS URLs, which matches Google's HTTPS requirement for non-localhost redirect URIs.
How to confirm it worked
- Open
https://staging--<site>.netlify.app, start Google sign-in, and check the browser console:auth/unauthorized-domainshould be gone. - After deploying the rewrite, open
https://www.example.com/__/auth/handler. You should get a response from Firebase's handler, not yourindex.html. If you see your app, the catch-all is matching first: check rule order and which file each rule is in. - Sign in on production. If Google shows
Error 400: redirect_uri_mismatch, the/__/auth/handlerURI is missing on the OAuth client.
Related problems
- The same error on Vercel previews: auth/unauthorized-domain on Vercel.
FAQ
Why does Firebase Auth work on my Netlify site but not on Deploy Previews?
Each pull request is deployed to deploy-preview-<number>--<site>.netlify.app, a hostname Firebase hasn't authorized. Authorize a branch deploy host for testing, or add a specific PR's host while it's open.
Is a Netlify Deploy Preview URL stable?
For one pull request, yes: it updates as you push to that PR. A new PR gets a new number and a new hostname, and each deploy's permalink (<deploy-id>--<site>.netlify.app) is new every time.
Where do I put the _redirects file?
In the publish directory Netlify deploys. For a Vite project, put it in public/ so the build copies it to dist/.
My /__/auth rule is in netlify.toml but Firebase's handler still shows my app. Why?
Netlify processes _redirects before netlify.toml and uses the first match, so a /* catch-all in _redirects wins. Move both rules into one file with the /__/auth/* rule first.
Should Deploy Previews use my custom authDomain?
No. The Google OAuth client must list the exact https://<host>/__/auth/handler URI for each custom authDomain, and preview hostnames change. Keep previews on <project-id>.firebaseapp.com with a [context.deploy-preview.environment] value.
Sources
- Deploy Previews (Netlify): Deploy Preview URL format, permalinks, agent run previews
- Branch deploys (Netlify): branch URL format, off by default, configuration path
- Automatic deploy subdomains (Netlify): Netlify DNS requirement, example URLs, permalinks per deploy
- Redirects and rewrites (Netlify): _redirects in publish directory, netlify.toml syntax, rule processing order
- Rewrites and proxies (Netlify): status 200 rewrites, proxy to another service, HTTPS note
- File-based configuration (Netlify): deploy contexts and context environment variables
- Next.js on Netlify (Netlify): redirects and rewrites support
- Static Asset Handling (Vite): public directory copied to dist
- Env Variables and Modes (Vite): VITE_ prefix exposed to client code
- Best practices for using signInWithRedirect (Firebase): Options 2 and 3, browser versions, handler URI
- Authenticate with Firebase using Email Link (Firebase): Security > Authentication > Settings > Authorized domains
- Set a web app's OAuth redirect domains (Firebase Help): full domain names
- Firebase JS SDK auth error messages (firebase-js-sdk on GitHub, errors.ts)
- Using OAuth 2.0 for Web Server Applications (Google Identity): HTTPS rule for redirect URIs
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.