firebase-js-sdk icon indicating copy to clipboard operation
firebase-js-sdk copied to clipboard

In Firebase Auth, using "Redirect Best Practices" prevents testing with localhost because it always uses HTTPS

Open aryehsanders opened this issue 1 year ago • 28 comments

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.

aryehsanders avatar Jun 01 '23 16:06 aryehsanders

Hi, could you try setting emulator flag to do testing with localhost and let us know if you still encounter the problem

bhparijat avatar Jul 11 '23 17:07 bhparijat

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.

aryehsanders avatar Jul 25 '23 11:07 aryehsanders

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.

aryehsanders avatar Jul 25 '23 12:07 aryehsanders

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}`;

aryehsanders avatar Jul 25 '23 13:07 aryehsanders

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.

bhparijat avatar Aug 03 '23 21:08 bhparijat

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.

aryehsanders avatar Aug 07 '23 13:08 aryehsanders

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.

anuraaga avatar Sep 22 '23 03:09 anuraaga

@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.

wallacepreston avatar Nov 03 '23 21:11 wallacepreston

We welcome any PRs with the potential fix mentioned by @aryehsanders

bhparijat avatar Nov 03 '23 21:11 bhparijat

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 avatar Jan 14 '24 11:01 stefan-hudelmaier

@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

isreehariojai avatar Apr 24 '24 04:04 isreehariojai

@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.

OmarBurney avatar May 03 '24 21:05 OmarBurney

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.

dipbhi avatar May 22 '24 13:05 dipbhi

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:

  1. Set authDomain to localhost or production-url based on current environment.
  2. Use Next.js Rewrites to create a reverse-proxy
  3. Add "authorized redirect uris" in Google Cloud.
  4. 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 avatar May 27 '24 13:05 reloaddev

@reloaddev, that guide works like a charm :100: even with Angular. I appreciate it a lot!

Adapted response for Angular:

[2] Reverse proxy:

  1. Create proxy.conf.json in root of your project:
{
  "/__/auth": {
    "target": "https://<project>.firebaseapp.com",
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug",
    "pathRewrite": {
      "^/__/auth": "/__/auth"
    }
  }
}
  1. in angular.json: "proxyConfig": "proxy.conf.json"

[4]

  1. set up certs:
  • generate certificate:
  npx office-addin-dev-certs install --days 365
  • copy certificate to firebase functions:
  cp ~/.office-addin-dev-certs/localhost.* .
  1. update angular.json "ssl": true, "sslKey": "localhost.key", "sslCert": "localhost.crt",

That's it!

ondrej-111 avatar May 29 '24 19:05 ondrej-111

It is juli now, and the new Firebase authDomain enforcement prevents using http://localhost now for real. Any solution to this?

rielzzapps avatar Jul 01 '24 11:07 rielzzapps

@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 !

tech-a-go-go avatar Jul 07 '24 20:07 tech-a-go-go

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.

tech-a-go-go avatar Jul 08 '24 04:07 tech-a-go-go

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.

yhuang1211 avatar Jul 08 '24 07:07 yhuang1211

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.

midnight-wonderer avatar Jul 15 '24 04:07 midnight-wonderer

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 avatar Jul 16 '24 18:07 hsubox76

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)

Lucisano avatar Jul 18 '24 10:07 Lucisano

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.

midnight-wonderer avatar Jul 18 '24 11:07 midnight-wonderer

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

Bigtalljosh avatar Jul 18 '24 12:07 Bigtalljosh

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.

anuraaga avatar Jul 18 '24 14:07 anuraaga