Avoid CORS preflight for Firebase callable function

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


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.