[javascript] Enabling CORS in Cloud Functions for Firebase

I'm currently learning how to use new Cloud Functions for Firebase and the problem I'm having is that I can't access the function I wrote through an AJAX request. I get the "No 'Access-Control-Allow-Origin'" error. Here's an example of the function I wrote:

exports.test = functions.https.onRequest((request, response) => {
  response.status(500).send({test: 'Testing functions'});
})

The function sits in this url: https://us-central1-fba-shipper-140ae.cloudfunctions.net/test

Firebase docs suggests to add CORS middleware inside the function, I've tried it but it's not working for me: https://firebase.google.com/docs/functions/http-events

This is how I did it:

var cors = require('cors');    

exports.test = functions.https.onRequest((request, response) => {
   cors(request, response, () => {
     response.status(500).send({test: 'Testing functions'});
   })
})

What am I doing wrong? I would appreciate any help with this.

UPDATE:

Doug Stevenson's answer helped. Adding ({origin: true}) fixed the issue, I also had to change response.status(500) to response.status(200) which I completely missed at first.

The answer is


Simple solution using the Google Cloud Console Dashboard:

  1. Go to your GCP console dashboard:

https://console.cloud.google.com/home/dashboard

  1. Go to menu

"Cloud Functions" ("Compute" section)

  1. Select your cloud function, e.g. "MyFunction", a side menu should appear on the right showing you the access control settings for it

  2. Click on "Add Member", type in "allUsers" and select the role "Cloud Function Invoker"

  3. Save it -> now, you should see a remark "Allow unauthenticated" in the list of your cloud functions

Access is now available to everybody from the internet with the correct config to your GCP or Firebase project. (Be careful)


If You are not using Express or simply want to use CORS. The following code will help resolve

const cors = require('cors')({ origin: true, });   
exports.yourfunction = functions.https.onRequest((request, response) => {  
   return cors(request, response, () => {  
        // *Your code*
    });
});

Only this way works for me as i have authorization in my request:

exports.hello = functions.https.onRequest((request, response) => {
response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); // vital
if (request.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    response.set('Access-Control-Allow-Methods', 'GET');
    response.set('Access-Control-Allow-Headers', 'Content-Type');
    response.set('Access-Control-Max-Age', '3600');
    response.status(204).send('');
} else {
    const params = request.body;
    const html = 'some html';
    response.send(html)
} )};

If there are people like me out there: If you want to call the cloud function from the same project as the cloud function it self, you can init the firebase sdk and use onCall method. It will handle everything for you:

exports.newRequest = functions.https.onCall((data, context) => {
    console.log(`This is the received data: ${data}.`);
    return data;
})

Call this function like this:

// Init the firebase SDK first    
const functions = firebase.functions();
const addMessage = functions.httpsCallable(`newRequest`);

Firebase docs: https://firebase.google.com/docs/functions/callable

If you can't init the SDK here is the essence from the other suggestions:


Adding my piece of experience. I spent hours trying to find why I had CORS error.

It happens that I've renamed my cloud function (the very first I was trying after a big upgrade).

So when my firebase app was calling the cloud function with an incorrect name, it should have thrown a 404 error, not a CORS error.

Fixing the cloud function name in my firebase app fixed the issue.

I've filled a bug report about this here https://firebase.google.com/support/troubleshooter/report/bugs


Changing true by "*" did the trick for me, so this is how it looks like:

const cors = require('cors')({ origin: "*" })

I tried this approach because in general, this is how this response header is set:

'Access-Control-Allow-Origin', '*'

Be aware that this will allow any domain to call your endpoints therefore it's NOT secure.

Additionally, you can read more on the docs: https://github.com/expressjs/cors


A cors error can occur if you don't catch an error in a function. My suggestion is to implement a try catch in your corsHandler

const corsHandler = (request, response, handler) => {
    cors({ origin: true })(request, response, async () => {
        try {
            await handler();
        }
        catch (e) {
            functions.logger.error('Error: ' + e);
            response.statusCode = 500;
            response.send({
                'status': 'ERROR' //Optional: customize your error message here
            });
        }
    });
};

Usage:

exports.helloWorld = functions.https.onRequest((request, response) => {
    corsHandler(request, response, () => {
        functions.logger.info("Hello logs!");
        response.send({
            "data": "Hello from Firebase!"
        });
    });
});

Thanks to stackoverflow users: Hoang Trinh, Yayo Arellano and Doug Stevenson


For what it's worth I was having the same issue when passing app into onRequest. I realized the issue was a trailing slash on the request url for the firebase function. Express was looking for '/' but I didn't have the trailing slash on the function [project-id].cloudfunctions.net/[function-name]. The CORS error was a false negative. When I added the trailing slash, I got the response I was expecting.


One additional piece of info, just for the sake of those googling this after some time: If you are using firebase hosting, you can also set up rewrites, so that for example a url like (firebase_hosting_host)/api/myfunction redirects to the (firebase_cloudfunctions_host)/doStuff function. That way, since the redirection is transparent and server-side, you don't have to deal with cors.

You can set that up with a rewrites section in firebase.json:

"rewrites": [
        { "source": "/api/myFunction", "function": "doStuff" }
]

For anyone trying to do this in Typescript this is the code:

import * as cors from 'cors';
const corsHandler = cors({origin: true});

export const exampleFunction= functions.https.onRequest(async (request, response) => {
       corsHandler(request, response, () => {});
       //Your code here
});

In my case the error was caused by cloud function invoker limit access. Please add allUsers to cloud function invoker. Please catch link. Please refer to article for more info


If none of the other solutions work, you could try adding the below address at the beginning of the call to enable CORS - redirect:

https://cors-anywhere.herokuapp.com/

Sample code with JQuery AJAX request:

$.ajax({
   url: 'https://cors-anywhere.herokuapp.com/https://fir-agilan.web.app/[email protected],
   type: 'GET'
});

No CORS solutions worked for me... till now!

Not sure if anyone else ran into the same issue I did, but I set up CORS like 5 different ways from examples I found and nothing seemed to work. I set up a minimal example with Plunker to see if it was really a bug, but the example ran beautifully. I decided to check the firebase functions logs (found in the firebase console) to see if that could tell me anything. I had a couple errors in my node server code, not CORS related, that when I debugged released me of my CORS error message. I don't know why code errors unrelated to CORS returns a CORS error response, but it led me down the wrong rabbit hole for a good number of hours...

tl;dr - check your firebase function logs if no CORS solutions work and debug any errros you have


I have just published a little piece on that:

https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html

Generally, you should use Express CORS package, which requires a little hacking around to meet the requirements in GCF/Firebase Functions.

Hope that helps!


This might be helpful. I created firebase HTTP cloud function with express(custom URL)

const express = require('express');
const bodyParser = require('body-parser');
const cors = require("cors");
const app = express();
const main = express();

app.post('/endpoint', (req, res) => {
    // code here
})

app.use(cors({ origin: true }));
main.use(cors({ origin: true }));
main.use('/api/v1', app);
main.use(bodyParser.json());
main.use(bodyParser.urlencoded({ extended: false }));

module.exports.functionName = functions.https.onRequest(main);

Please make sure you added rewrite sections

"rewrites": [
      {
        "source": "/api/v1/**",
        "function": "functionName"
      }
]

Found a way to enable cors without importing any 'cors' library. It also works with Typescript and tested it in chrome version 81.0.

exports.createOrder = functions.https.onRequest((req, res) => {
// browsers like chrome need these headers to be present in response if the api is called from other than its base domain
  res.set("Access-Control-Allow-Origin", "*"); // you can also whitelist a specific domain like "http://127.0.0.1:4000"
  res.set("Access-Control-Allow-Headers", "Content-Type");

  // your code starts here

  //send response
  res.status(200).send();
});

From so much searching, I could find this solution in the same firebase documentation, just implement the cors in the path:

import * as express from "express";
import * as cors from "cors";


const api = express();
api.use(cors({ origin: true }));
api.get("/url", function);

Link firebase doc: https://firebase.google.com/docs/functions/http-events


If you're testing firebase app locally then you need to point functions to localhost instead of cloud. By default, firebase serve or firebase emulators:start points the functions to server instead of localhost when you use it on your web app.

Add below script in html head after firebase init script:

 <script>
      firebase.functions().useFunctionsEmulator('http://localhost:5001')
 </script> 

Make sure to remove this snippet when deploying code to server.


If you don't/can't use cors plugin, calling the setCorsHeaders() function first thing in the handler function will also work.

Also use the respondSuccess/Error functions when replying back.

const ALLOWED_ORIGINS = ["http://localhost:9090", "https://sub.example.com", "https://example.com"]


// Set CORS headers for preflight requests
function setCorsHeaders (req, res) {
  var originUrl = "http://localhost:9090"


  if(ALLOWED_ORIGINS.includes(req.headers.origin)){
    originUrl = req.headers.origin
  }

  res.set('Access-Control-Allow-Origin', originUrl);
  res.set('Access-Control-Allow-Credentials', 'true');

  if (req.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    res.set('Access-Control-Allow-Methods', 'GET,POST','PUT','DELETE');
    res.set('Access-Control-Allow-Headers', 'Bearer, Content-Type');
    res.set('Access-Control-Max-Age', '3600');
    res.status(204).send('');
  }
}

function respondError (message, error, code, res) {
  var response = {
    message: message,
    error: error
  }
  res.status(code).end(JSON.stringify(response));
}


function respondSuccess (result, res) {
  var response = {
    message: "OK",
    result: result
  }
  res.status(200).end(JSON.stringify(response));
}

I have a little addition to @Andreys answer to his own question.

It seems that you do not have to call the callback in the cors(req, res, cb) function, so you can just call the cors module at the top of your function, without embedding all your code in the callback. This is much quicker if you want to implement cors afterwards.

exports.exampleFunction = functions.https.onRequest((request, response) => {
    cors(request, response, () => {});
    return response.send("Hello from Firebase!");
});

Do not forget to init cors as mentioned in the opening post:

const cors = require('cors')({origin: true});


You can set the CORS in the cloud function like this

response.set('Access-Control-Allow-Origin', '*');

No need to import the cors package


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to firebase

How can I solve the error 'TS2532: Object is possibly 'undefined'? Getting all documents from one collection in Firestore FirebaseInstanceIdService is deprecated Failed to resolve: com.google.firebase:firebase-core:16.0.1 NullInjectorError: No provider for AngularFirestore Firestore Getting documents id from collection How to update an "array of objects" with Firestore? firestore: PERMISSION_DENIED: Missing or insufficient permissions Cloud Firestore collection count iOS Swift - Get the Current Local Time and Date Timestamp

Examples related to google-cloud-platform

GoogleMaps API KEY for testing How to change the project in GCP using CLI commands Enabling CORS in Cloud Functions for Firebase Get root password for Google Cloud Engine VM gcloud command not found - while installing Google Cloud SDK What is the difference between Google App Engine and Google Compute Engine? How to open a specific port such as 9090 in Google Compute Engine Google server putty connect 'Disconnected: No supported authentication methods available (server sent: publickey) How to use Google App Engine with my own naked domain (not subdomain)?

Examples related to cors

Axios having CORS issue Cross-Origin Read Blocking (CORB) Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource How to allow CORS in react.js? Set cookies for cross origin requests XMLHttpRequest blocked by CORS Policy How to enable CORS in ASP.net Core WebAPI No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API How to overcome the CORS issue in ReactJS Trying to use fetch and pass in mode: no-cors

Examples related to google-cloud-functions

How can I solve the error 'TS2532: Object is possibly 'undefined'? Enabling CORS in Cloud Functions for Firebase