CORS blocking access to resource: How to fix in firebase cloud function?

Viewed 2805

Yes, I have the dreaded CORS issue (or, at least it appears so)....and I have searched and tried a few solutions, to no avail...

I have no problems using firebase emulator and running my function locally, but when I deploy the function and try to send a POST request using fetch() on the local host client-side app, I get the following CORs browser console error (it won't even get to the server logs):

Access to fetch at 'https://us-central1-XXXX.cloudfunctions.net/deleteAsset' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: 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.

The FetchEvent for "https://us-central1-XXXXX.cloudfunctions.net/deleteAsset" resulted in a network error response: the promise was rejected.

Promise.then (async)
(anonymous) @ firebase-auth-sw.js:77
firebase-auth-sw.js:77 
        
 Uncaught (in promise) TypeError: Failed to fetch
    at firebase-auth-sw.js:77

Here's my client side fetch request:

UploadImage.vue:

async deleteFile() {
      await fetch(
        'https://us-central1-XXXX.cloudfunctions.net/deleteAsset',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            public_id: this.imageSrc.public_id
          })
        }
      )
}

And then my firebase cloud function is like so:

/deleteAsset.js:

import cloudinary from 'cloudinary'
import * as functions from 'firebase-functions'

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

cloudinary.config({
  cloud_name: functions.config().cloudinary.cloud_name,
  api_key: functions.config().cloudinary.api_key,
  api_secret: functions.config().cloudinary.api_secret,
  secure: true
})


export const deleteAsset = functions.https.onRequest((req, res) => {
  return cors(req, res, () => {
    try {
      functions.logger.log(req.body)
      cloudinary.v2.uploader.destroy(
        req.body.public_id,
        {
          invalidate: true
        },
        (error, result) => {
          if (error) {
            res.status(500).send(error)
          }

          res.status(200).send(result)
        }
      )
    } catch (error) {
      res.status(500).send('There was an error in deleteAsset function')
    }
  })
})

Anyone spot any issues or have any advice on how I can further troubleshoot this?

2 Answers

Alright, so I fixed it....the CORS issue was due to the cloud function not having the right IAM permissions. I suspected it after looking at my dashboard (not shown on firebase console, had to go to Cloud Functions over at Google Cloud to see it!) and noticed that it was missing "Allow Unauthenticated". So, I manually deleted the function and redeployed. All good now!

enter image description here

In your cors's options, you're not setting localhost as a valid source.

Change the code from this

export const deleteAsset = functions.https.onRequest((req, res) => {
  return cors(req, res, () => {
    try {

to this

export const deleteAsset = functions.https.onRequest((req, res) => {
  return cors({origin: 'http://localhost:3000'}, req, res, () => {
    try {

You should add all the origins you'll use, not only localhost. For furhter details on how to specify the allowed origins, take a look at the documentation.

Related