0

I have a simple firebase function that returns a hello world

exports.myFunc = functions
    .runWith({
        maxInstances: 1,
        memory: "128MB"
    })
    .https.onRequest(async (request, response) => {
        response.set("Content-Type", "text/plain");
        response.status(200).send('Hello world!');
    }

I am calling it with a POST request with these headers:

>  {
>    host: 'localhost:5001',
>    connection: 'keep-alive',
>    pragma: 'no-cache',
>    'cache-control': 'no-cache',
>    accept: '*/*',
>    'access-control-request-method': 'POST',
>    'access-control-request-headers': 'authorization,content-type',
>    origin: 'http://localhost:8080',
>    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
>    'sec-fetch-mode': 'cors',
>    'sec-fetch-site': 'same-site',
>    'sec-fetch-dest': 'empty',
>    referer: 'http://localhost:8080/',
>    'accept-encoding': 'gzip, deflate, br',
>    'accept-language': 'en-US,en;q=0.9'
>  }

The problem is I'm running into CORS errors when I try and call it, as I'm calling it from a vue app hosted on firebase. Ok, makes sense, so I read some documentation on CORS, and the first error it was throwing was:

from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Ok, I add the required header:

exports.myFunc = functions
    .runWith({
        maxInstances: 1,
        memory: "128MB"
    })
    .https.onRequest(async (request, response) => {
        if (request.method === 'OPTIONS') {
            response.set('Access-Control-Allow-Origin', '*');
            response.status(204).send('');
        } else {
            // return hello world 
        }
    }

I'm aware allowing all (*) is a bad security practice and defeats some of the purpose of CORS but this is for testing. With the above setup i get another CORS error:

from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.

Ok, I add some more headers:

exports.myFunc = functions
    .runWith({
        maxInstances: 1,
        memory: "128MB"
    })
    .https.onRequest(async (request, response) => {
        if (request.method === 'OPTIONS') {
            response.set('Access-Control-Allow-Headers', "authorization,content-type");
            response.set('Access-Control-Allow-Origin', '*');
            response.status(204).send('');
        } else {
            // return hello world 
        }
    }

BUT ADDING THAT HEADER GIVES ME THE SAME ERROR FROM THE FIRST! :

from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I have tried all the random headers combinations, auth header, credentials header, enabling all header methods, etc. NO COMBINATION SEEMS TO WORK what am I doing wrong? All answers I find online tell me adding

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

Is the solution, but its not working? One solution causes another error and so on so on.

Here is the return header I'm returning:

>  [Object: null prototype] {
>    'x-powered-by': 'Express',
>    'access-control-allow-headers': 'authorization,content-type',
>    'access-control-allow-origin': '*'
>  }
Oirampok
  • 569
  • 5
  • 23

1 Answers1

0

So I figured out the cause, and it was a number of things that went wrong, hopefully this helps someone with the same error as me in the future.

  1. When dealing with CORS, you need to make sure that you are sending the required headers in the response of the initial CORS preflight request and THE ACTUAL REQUEST THAT COMES AFTER. What was happening in my case was I was returning the correct headers for the options preflight request, but not the actual request that comes after.

  2. If you are using chrome to debug, you can set the developer console to show both the preflight and actual request. My version of chrome was combining to the two requests which led me to believe all this time it was the preflight that was still causing issues. You can change your chrome settings by following this answer: Chrome not showing OPTIONS requests in Network tab.

  3. Finally, in the end the fix was very simple, just adding the required cors header again in the actual request fixed everything. Here is the code:

     .https.onRequest(async (request, response) => {
    
         if (request.method === 'OPTIONS') {
             response.set('Access-Control-Allow-Headers', "authorization,content-type");
             response.set('Access-Control-Allow-Origin', '*');
             response.status(204).send('');
         } 
         else {
             // return hello world 
             response.set('Access-Control-Allow-Origin', '*');
         }
    

Notice the response will now also return the access control allow origin header regardless if its a preflight options req or the actual request.

Oirampok
  • 569
  • 5
  • 23