firebase-js-sdk
firebase-js-sdk copied to clipboard
In Firebase Auth, using "Redirect Best Practices" prevents testing with localhost because it always uses HTTPS
Operating System
Windows
Browser Version
Firefox 113
Firebase SDK Version
9.22.1
Firebase SDK Product:
Auth
Describe your project's tooling
Vue with Vite
Describe the problem
Following https://firebase.google.com/docs/auth/web/redirect-best-practices, it appears that our app should supply the current host as the authDomain. For development, we want to use localhost:3000
. In bug #7233, it appeared that this should now support a value of localhost:3000
, but when I tried it, it fails with an error because it tries to redirect to http*s*://localhost:3000/...
.
This appears to be because in packages/auth/src/core/util/handler.ts
in getHandlerBase
there is a hard-coded https
in the URL, but localhost requires http
.
Steps and code to reproduce issue
Use signInWithRedirect with an authDomain of localhost:3000. It will redirect to HTTPS.
Hi, could you try setting emulator flag to do testing with localhost and let us know if you still encounter the problem
Thanks for responding; sorry I didn't notice sooner. This isn't a substitute for using our development code with real Firebase; now that some browsers have disabled third-party cookies, it has become difficult to be sure that our flows will work for real, and the hard-coded 'https:' in the client auth code prevents us from running a local test (with the local part acting as the developer's server) against the non-emulated real Firebase remote servers.
Just to be thorough, I did test with the emulator anyway, and sure enough, it doesn't work for auth in Firefox because of the third-party cookie partitioning change that lead to the Redirect Best Practices document. It does work on Chrome, which has not yet limited third-party cookies, but that's not helpful for testing what will happen to our Firefox and Safari users.
If code would make the issue clearer - a small patch (untested!) in handler.ts would fix this: Instead of:
return `https://${config.authDomain}/${WIDGET_PATH}`;
Replace with:
const isLocalhost = config.authDomain.split(':')[0] === 'localhost';
return (isLocalhost ? 'http' : 'https') + `://${config.authDomain}/${WIDGET_PATH}`;
Hi @aryehsanders, please provide an HAR file and share what your code config looks like for using emulator?
And, is your app hosted on http://localhost ? Could you try setting up TLS certificates on localhost? That way the communication from IDP to the oauth helper code will be over https (encrypted) than http.
I can provide the whole HAR file, but it's really not helpful. Firefox itself explains in the dev console:
Partitioned cookie or storage access was provided to “http://127.0.0.1:9099/emulator/auth/iframe?apiKey=AIzaSyDQDLCIq5syV05gAZTkwwjXMHaQP5x17IA&appName=%5BDEFAULT%5D-firebaseui-temp&v=9.22.1&eid=p&usegapi=1&jsh=m%3B%2F_%2Fscs%2Fabc-static%2F_%2Fjs%2Fk%3Dgapi.lb.en.S9zOXUg9rrA.O%2Fd%3D1%2Frs%3DAHpOoo-AXjUK4hNAaKzui0P9Fr9nG2_yZQ%2Fm%3D__features__#id=I0_1691412046814&_gfid=I0_1691412046814&parent=http%3A%2F%2Flocalhost%3A5000&pfname=&rpctoken=18705812” because it is loaded in the third-party context and dynamic state partitioning is enabled.
Once Firefox and Safari enabled partitioned storage access, logins that depend on common storage, such as Firebase Auth, won't work between two contexts. In this case, one context is the emulator, at http://127.0.0.1:9099, and the other is my test server at http://localhost:3000. Without the emulator, there are various workarounds, as documented in Firebase's own Redirect Best Practices document.
In other words - you can use any setup, and any app on localhost with the emulator, and you can no longer log in using signinWithRedirect
in Firefox.
Regarding your other questions:
And, is your app hosted on http://localhost/ ?
No, our app is usually hosted on our own URL, and it works, even in Firefox. However, there's no way to test our code on my own developer machine.
Could you try setting up TLS certificates on localhost? That way the communication from IDP to the oauth helper code will be over https (encrypted) than http.
Yes, this should work. This is far more complicated than just giving up and posting a copy to a dev site, even though that would mean a very slow cycle for trying new code. I'd have to create a new certificate and have each developer add it to their machine's trusted store. You cannot get a real certificate for localhost. I'd also have to reconfigure the local server (in our case, the Vue dev server) to use my certificate and use HTTPS. This is not a realistic path for most developers. It's certainly easier just to change the one line in Firebase locally to use HTTP. I would hope that Firebase would want to support developers testing their work locally before publishing changes, and that Firebase doesn't expect developers to go to extreme measures to be able to do so.
Ran into this as well, we can easily configure webpack dev server to proxy requests through localhost to the firebase auth handler, which should solve issues with 3rd party cookies as per the linked doc for redirect best practices, but the hard-coded scheme for handler URLs makes it not work. https://github.com/firebase/firebase-js-sdk/issues/7342#issuecomment-1649803984 is a good example but because it is possible (but not developer-friendly) to use https with localhost, it can't be a blanket conversion, but I noticed there is an apiScheme
flag on auth config
https://github.com/firebase/firebase-js-sdk/blob/e30d7a6522fd3be0c30a82ee054b271a68c03fde/common/api-review/auth.api.md?plain=1#L275
Setting it to http
causes requests to identity toolkit to be http, which naturally fails. If there were an additional flag, authScheme
or similar that was used when creating the handler URLs, we would be able to use it in typical local development environments which will help a lot. As the linked doc states, starting June 2024 even Chrome will not work with the current scheme, and due to developer experience issues with requiring TLS on localhost servers, this seems like something that needs to be looked at relatively soon.
@aryehsanders @anuraaga were you able to resolve this? I'm running into a similar issue. When proxying localhost requests from __/auth
to the firebase app, it enforces https, and disables the login.
We welcome any PRs with the potential fix mentioned by @aryehsanders
I'm not sure if it's exactly the same issue, but I solved it by using the default (non-custom) auth domain when running locally:
const authDomain = process.env.NODE_ENV === 'development' ? 'myapp.firebaseapp.com' : mycustomdomain.com';
This way, signInRedirect works again when running on localhost.
@stefan-hudelmaier your localhost will stop working in all browsers when you*.firebaseapp.com
from - June 18, 2024 - https://firebase.google.com/docs/auth/web/redirect-best-practices
@stefan-hudelmaier your localhost will stop working in all browsers when you
*.firebaseapp.com
from - June 18, 2024 - https://firebase.google.com/docs/auth/web/redirect-best-practices
Do you have any suggestions on how to make proxying work with firebase auth on localhost using http?
Using the comments above I was able to get it working for https, but like others would to get it working for http instead.
The current blocker is initializeApp() automatically sets the transport to https, and none of the firebase options give control to switch to http.
Redirect best practices option 1 is working fine with firebase 10.9.0 when using the [mydomain].firebaseapp.com domain. It didn't work in localhost with a custom domain, so as a workaround I switched to using firebaseapp.com domain locally.
For people who use Next.js and do not use Firebase Hosting, try option 3 from https://firebase.google.com/docs/auth/web/redirect-best-practices. I could make it work by following these steps:
- Set
authDomain
to localhost or production-url based on current environment. - Use Next.js Rewrites to create a reverse-proxy
- Add "authorized redirect uris" in Google Cloud.
- Use --experimental-https flag to make localhost https
[1] In firebase.ts
, replace the authDomain
based on the current environment.
const env = process.env.NODE_ENV
if (env == "development") {
firebaseConfig.authDomain = "localhost:<port>";
} else if (env == "production") {
firebaseConfig.authDomain = "<production-url>";
}
[2] In next.config.mjs, add a Rewrite to proxy requests to /__/auth/:path* to Firebase Auth
async rewrites() {
return [
{
source: '/__/auth/:path*',
destination: 'https://<project>.firebaseapp.com/__/auth/:path*',
},
]
},
[3] In Google Cloud > API & Services > Credentials > OAuth 2.0 Client IDs > <Your Project>, add under "Authorized redirect URIs" the following uris:
- https://localhost:[PORT]
- https://localhost:[PORT]/__/auth/handler
- https://[PRODUCTION_URL]
- https://[PRODUCTION_URL]/__/auth/handler
From Google Cloud: "Note: It may take 5 minutes to a few hours for settings to take effect" <-- I second that, for me it was 1-2 hours actually.
[4] If you start your Next.js application now in development mode, e.g. next dev
, make sure to add the --experimental-https
flag to make localhost use https. With that, you should be able to use signInWithRedirect
in all browsers, including Safari and Firefox.
@reloaddev, that guide works like a charm :100: even with Angular. I appreciate it a lot!
Adapted response for Angular:
[2] Reverse proxy:
- Create proxy.conf.json in root of your project:
{
"/__/auth": {
"target": "https://<project>.firebaseapp.com",
"secure": false,
"changeOrigin": true,
"logLevel": "debug",
"pathRewrite": {
"^/__/auth": "/__/auth"
}
}
}
- in angular.json: "proxyConfig": "proxy.conf.json"
[4]
- set up certs:
- generate certificate:
npx office-addin-dev-certs install --days 365
- copy certificate to firebase functions:
cp ~/.office-addin-dev-certs/localhost.* .
- update angular.json "ssl": true, "sslKey": "localhost.key", "sslCert": "localhost.crt",
That's it!
It is juli now, and the new Firebase authDomain enforcement prevents using http://localhost now for real. Any solution to this?
@reloaddev Thanks for your comment ! That helped me a lot.
But now I get an error FirebaseError: Firebase: Error (auth/admin-restricted-operation).
on await getRedirectResult(auth)
after redirected back to my https://localhost:3000 tho.
(I'm getting 'Third-party cookie will be blocked. Learn more in the Issues tab.' on console of chrome dev tools. Does this cause the error ...?)
Any clues you have ?
Thank you !
I found out what was the problem.
I've disabled "user creation by user" on firebase project page for email,password auth earlier.
That prevented the redirect login with error FirebaseError: Firebase: Error (auth/admin-restricted-operation)
Allowing "user creation by user" fixed the problem.
Thank you.
I can't signInWithRedirect on local dev machine anymore. It's quite painful to re-deploy my web app onto the cloud to test something changed every time. Is there an ETA for the localhost http fix? If not I'll have to start converting local dev to https.
Hi, Can we just do the simple thing as @anuraaga suggested?
Like this: https://github.com/firebase/firebase-js-sdk/compare/master...midnight-wonderer:firebase-js-sdk:feature/auth-scheme-for-local-development It's just a pseudocode as POC, though.
I like this one because it is consistent with the existing option.
We welcome any PRs with the potential fix mentioned by @aryehsanders
I think the auth team is welcoming PRs on this, that might be the fastest way to get this solved.
Bumping this, everything was working fine for local flow using default Auth domain then I get back from holiday and the whole flow is broken
We welcome any PRs with the potential fix mentioned by @aryehsanders
I think the auth team is welcoming PRs on this, that might be the fastest way to get this solved.
@hsubox76 is there a public support ticket for this with Google? I'd like to monitor as it's caused another massive headache for us developing with Firebase auth. (Which is nothing new as firebase auth has just been a headache from the beginning)
Reply to @hsubox76
I think the auth team is welcoming PRs on this, that might be the fastest way to get this solved.
When I tried to create a new PR, the template said to discuss it first.
So, I posted my changes here to discuss.
Why I think it is also alternatively better for project members to handle this
- The PR is time-consuming for anyone new to the project; despite having the changes readied, there is still a long way to go. I can't run the tests locally just yet; I hope I can rely on the CI in the actual PR.
- The environment setup is not simple; it is not simply an
npm run test
.
I can do it, but it can optionally be picked up by the project members for faster and more correct integration without me investing in the project for a one-off PR.
Tips for those affected
(If you haven't worked around your development issues already.) This is what I do in my project:
- A Backdoor for the development environment; don't expose it to production. The backdoor lets people log in as any account, bypassing Firebase altogether.
- Despite having a backdoor, some of your team, potentially not the majority, will have to test integration with Firebase anyway. While I don't like advertising other products, I would point to Cloudflare Tunnel; it lets you expose local ports as HTTPS. There are several different solutions, including just using SSH to forward local ports to remote Nginx with Let's Encrypt. IMHO, Cloudflare Tunnel is a cost-effective way (free, dollar-wise) that balances usability and trust.
Reply to @hsubox76
I think the auth team is welcoming PRs on this, that might be the fastest way to get this solved.
When I tried to create a new PR, the template said to discuss it first. So, I posted my changes here to discuss.
Before you dupe effort, there seems to be a PR open for this issue that's gone a little stale https://github.com/firebase/firebase-js-sdk/pull/7783
I'd say @midnight-wonderer's general sentiment still stands, this issue requires some technical leadership for a real fix. The linked PR would break the opposite case, developers that actually use TLS with localhost (not as common yes but not zero), and currently don't have any issue, will break. So there are various UX decisions that need to be made by stakeholders I think.