Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid CORS preflight for Firebase callable function

I have a Firebase Callable Cloud Function which I call in my javascript app in the browser.

Because the request host is ...cloudfunctions.net and not my app domain this results in a CORS preflight OPTIONS request before the real POST request.

If this was a function with http trigger I'd avoid the extra time that the preflight takes by specifying my function as a rewrite in my hosting config and sending the request to the same domain my app is hosted on.

Is there any way to avoid this preflight with Firebase Callable Cloud Functions? Perhaps there's a way to proxy the request through Firebase Hosting, like you can with http Cloud Functions

like image 563
Jake Avatar asked Mar 26 '19 08:03

Jake


2 Answers

After combing through Firebase docs and JS SDK source I've decided this is not possible without using/overriding private APIs.

The solution I've used is to replicate the JS SDK code but specifying a URL that goes via Firebase Hosting so it's on the same domain as my app.

Same Cloud Function, same app code, no CORS preflight 👍🏼


  1. Create a normal Firebase Callable Cloud Function
  2. Add a rewrite to firebase.json
{
 ...
 "hosting": {
   ...
   "rewrites": [
      {
        "source": "myFunction",
        "function": "myFunction"
      }
   ]
 }
}
  1. Instead of calling it with firebase.functions().httpsCallable('myFunction') send a POST request to your own new URL
const token = await firebase.auth().currentUser.getIdToken()
const response = await fetch(
  'https://myapp.web.app/myFunction',
  {
    headers: {
      'Content-Type': 'application/json',
      Authorization: 'Bearer ' + token
    },
    method: 'post',
    body: JSON.stringify({ data })
  }
)

Now the URL is within your domain so no CORS issues

like image 183
Jake Avatar answered Oct 03 '22 07:10

Jake


For users who have the CORS preflight problem with the firebase local emulator, if you're using Webpack or Vue (vue-cli), you can resolve the situation with a proxy:

my-firebase-initialize-file.js (client side)

firebase.initializeApp(...); // your config
firebase.functions().useFunctionsEmulator('http://localhost:1234/api'); // Client url + /api

webpack.config.js or vue.config.js (client side, at the root, next to package.json)

module.exports = {
  devServer: {
    proxy: {
      "^/api": {
        target: "http://localhost:5001", // Emulator's url
        pathRewrite: {
          "^/api": ""
        },
        ws: true,
        changeOrigin: true
      }
    }
  }
};

Now every http://localhost:1234/api will be proxied to http://localhost:5001, so you don't need CORS preflight anymore.

Of course you need to adapt these local urls to your case.

like image 31
mlb Avatar answered Oct 03 '22 07:10

mlb