2

I have been trying to invoke a Firebase Cloud Function without success.

The sucessfully deployed function is:

functions.logger.info("Hello logs!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); // this logs
exports.createAuthToken = functions.https.onRequest((request, response) => {
    functions.logger.info("Hello logs!", { structuredData: true }); // this doesn't log
    response.send("Hello from Firebase!");
});

The first line of the code shows up in the logs, but the third line doesn't when called from an external web client. When I test / run the function from the Google Cloud console, both logs show up.

In the web client, I get the error message:

Access to fetch at 'https://us-central1-my-project.cloudfunctions.net/create-auth-aoken?ot-auth-code=xyz' from origin 'https://my-client-url' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

So I resolve the cors issue as the documentation suggests like this:

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

functions.logger.info("Hello logs!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); // this logs
exports.createAuthToken = functions.https.onRequest((request, response) => {
    cors(request, response, () => {
        functions.logger.info("Hello logs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>!", { structuredData: true }); // this still doesn't 
        response.send("Hello from Firebase!");
    });
});

I am calling the function like this: https://us-central1-my-project.cloudfunctions.net/create-auth-token?ot-auth-code=${code}&id-token=${token} I have tried resolving the cors problem in every way I can possibly find, but it will not work.

How should I configure this exactly to make it work?

Mr. Robot
  • 1,334
  • 6
  • 27
  • 79

3 Answers3

1

This could be addressed in several ways, one is by sending your request to a proxy server. Your request would look like this:

https://cors-anywhere.herokuapp.com/https://joke-api-strict-cors.appspot.com/jokes/random

This is an easy solution and works for dev environmeent as it is implemented on browser-to-server communication. The downsides are that your request may take a while to receive a response as high latency makes it appear to be slow, and may not be not ideal for production environment.

Another option is to try using CORS with Express. Check the Node.js code below:

const express = require('express');
const request = require('request');

const app = express();

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  next();
});

app.get('/jokes/random', (req, res) => {
  request(
    { url: 'https://joke-api-strict-cors.appspot.com/jokes/random' },
    (error, response, body) => {
      if (error || response.statusCode !== 200) {
        return res.status(500).json({ type: 'error', message: err.message });
      }

      res.json(JSON.parse(body));
    }
  )
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`listening on ${PORT}`));

This one would act as a middleware to apply Access-Control-Allow-Origin: * header to every request from the server. Same-origin policy will not step in to block the request even though the domains are different.

You may check the full documentations on how to fix CORS error:

Robert G
  • 1,583
  • 3
  • 13
  • Thank you @Robert G! I will look in to these solutions. But you are saying that what I am trying to do is simply not possible with a straight client to cloud function solution like mine? – Mr. Robot Oct 27 '21 at 06:51
  • 1
    There are many ways to enable CORS in Firebase Function. The sample code in my answer simply uses CORS with Express. – Robert G Oct 27 '21 at 07:55
1

It certainly is possible; I use this solution for firebase which I rolled myself to simply respond to CORS requests:

 function MakeCORSRequest(func) {
  return functions.https.onRequest((req, res) => {
    res.set('Access-Control-Allow-Origin', '*');
    if (req.method === 'OPTIONS') {
      // Send response to OPTIONS requests
      res.set('Access-Control-Allow-Methods', 'GET, POST');
      res.set('Access-Control-Allow-Headers', 'Content-Type');
      res.set('Access-Control-Max-Age', '3600');
      res.status(204).send('');
    } else {
      return func(req, res);
    }
  });
}

All it does is intercept CORS OPTIONS request and respond with 'Yes you can' - other requests (such as GET/POST) it just passes forward to the given function. It can be used to wrap your endpoint and respond correctly to CORS calls coming from the browser.

So the actual end point is expressed like this:

exports.myFunction = MakeCORSRequest(async (req, response) => {
   //Do your stuff here
})
Elemental
  • 7,365
  • 2
  • 28
  • 33
  • Thanks @Elemental, I've used your exact code, but when I call the function from a React app served on Netlify, I still get the CORS error. – Mr. Robot Oct 27 '21 at 16:46
  • My code above only allows GET and POST if you are using other bits you'll need to modify it – Elemental Oct 28 '21 at 11:33
  • it shouldn't matter where you call the function FROM - are you sure you understand my second bit of code (i.e. instead of using function.https.onRequest you need to use the MakeCORSRequest for ALL of your endpoint functions) – Elemental Oct 28 '21 at 13:13
1

I wasn't able to solve the CORS issue but I did manage to make the cloud function work eventually by using functions.https.onCall instead of functions.https.onRequest. I found this answer https://stackoverflow.com/a/51477892/11584105 and followed these official docs: https://firebase.google.com/docs/functions/callable#web-version-9

Mr. Robot
  • 1,334
  • 6
  • 27
  • 79