0

The following is the client-side code to call the cloud function:

// add a new post
addPostForm.addEventListener('click', (e) => {
  e.preventDefault();
  
  const addPost = httpsCallable(functions, 'addPost');
  addPost({
    title: addPostForm.postTitle.value,
    description: addPostForm.postDescription.value,
  })
  .then(() => {
    addPostForm.reset(),
    addPostModal.classList.remove('open');
    addPostForm.querySelector('.error').textContent = '';
  })
  .catch(error => {
    addPostForm.querySelector('.error').textContent = error.message;
  })
});

The cloud function:

exports.addPost = functions.https.onCall((data, context) => {
    if(!context.auth){
        throw new functions.https.HttpsError(
            'unauthenticated',
            'only authenticated users can post'
        );
    }
    if(data.text.length > 140){
        throw new functions.https.HttpsError(
            'invalid-argument',
            'description must be no more than 140 characters long'
        );
    }
    return admin.firestore().collection('Posts').add({
        title: data.title,
        description: data.description,
        likes: '',
        bookmarks: '',
    });
});

Firebase Setup:

import { initializeApp, getApp } from "firebase/app";
import { getAuth, connectAuthEmulator } from "firebase/auth";
import { getStorage, connectStorageEmulator } from "firebase/storage";
import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";
import { getFunctions, connectFunctionsEmulator } from "firebase/functions";

const firebaseConfig = {
"config"
  };
  
  // Initialize Firebase 
  const app = initializeApp(firebaseConfig);

  const auth = getAuth(app);
  const db = getFirestore(app);
  const storage = getStorage(app);
  const functions = getFunctions(getApp(), app);
  
  if (window.location.hostname.includes("localhost")) {
    connectAuthEmulator(auth, "http://localhost:9099");
    connectFirestoreEmulator(db, 'localhost', 8080);
    connectStorageEmulator(storage, 'localhost', 9199);
    connectFunctionsEmulator(functions, "localhost", 5001);
}

  export { auth, db, storage, functions };

Error Access to fetch at 'http://localhost:5001/app/object/addPost' From origin 'http://localhost:5173' 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.

What's the problem here? Will I need to set up firebase admin to grant access rights, and if I turn CORS off in the browser will that present a security issue on production?

HarryNC
  • 97
  • 8

2 Answers2

1

After over a week of learning and trying to find the right solution for this problem, I came across a video from one of my favorite YT creators Web Dev Simplified.

Here he elegantly explains the CORS error and provides a simple yet effective solution. Installing the Express and CORS library through NPM within my cloud functions folder and requiring them both in the index.js file. Writing a function that allows you to change the access origin should be enough to solve this error.

const express = require("express");
const app = express();
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const cors = require('cors');
app.use(
    cors({
        origin: "*",
    })
);

Changing the origin to "*" allows the access request origin to be from any source. You can also change this to a specific URL if you needed.

HarryNC
  • 97
  • 8
0

CORS error occurs when the request from a certain origin (eg. abc.com) is restricted to access resources on another origin (eg. xyz.com). This is a security measure enforced at the browser level and this is not related to Firebase setup.

There are two ways through which this can be solved,

  1. Disable CORS in the browser. This is NOT recommended and should not be done for most cases.

  2. If you are in control of the server, then you can modify your application to receive requests from a certain source. In this case, you are in control of both the server and the client. you just have to configure the server application (Cloud Functions in this case) to accept requests from the client. For this, in the CF code, you can set the header Access-Control-Allow-Origin to the value of the client origin (Eg. localhost:PORT_NUM) or simply set the value to * to receive requests from all client origins.

As mentioned in the Answer, you can follow the checklist for the firebase callable functions cors errors :

  1. Ensure the function is deployed.
  2. Ensure the function name is correct. I was calling recalculatY when it should have been recalculateY. Got a cors error for some reason.
  3. Ensure the function code itself is not throwing an error. Use the emulator to help. This didn't throw a cors error, still helpful to know.
  4. Ensure your regions match - I am using europe-west2. I had to both deploy the function with that region, and call it using the region. For a while, I assumed the client would infer the correct region if the function name was correct.

you can refer to the Documentation which explains about how to connect your app to cloud function emulator.

For more information , you can refer to the Answer and git issue.

Divyani Yadav
  • 1,030
  • 4
  • 9
  • thank you for the answer, I have found similar information to this but have also not been able to act upon it in a way that I trust will solve my issue, now in the emulator (testing) and deployed for production. I'm new to coding and I'm teaching myself to get this app built. It would be massively helpful to get some guidance on this topic with the current firebase modular framework and whilst using the emulator. – HarryNC Aug 31 '22 at 15:58
  • @HarryNC I have updated my answer and shared some Firebase Public Documentation for knowledge , is it helpful? – Divyani Yadav Aug 31 '22 at 17:11
  • @divysniyadav Okay thanks this last link may help - I have tried all of the above and have not seemed to get it to work. If I copy these functions that produce a bearer ID token will that work? [https://github.com/firebase/functions-samples/blob/main/authorized-https-endpoint/functions/index.js]. I have to be honest this is going way over my head currently. What would be helpful is a video going over this specific thing I just can't seem to find a good one. – HarryNC Aug 31 '22 at 17:40
  • here is a [video](https://www.youtube.com/watch?v=H0rZnxRV7_k) and [playlist](https://www.youtube.com/playlist?list=PL8jcXf-CLpxrEK4OJMEepopW02LpSuH4Z) that might help. – Divyani Yadav Sep 01 '22 at 12:32
  • thanks for sharing these. I'm still getting the error after implementing these CORS fixes. Could it be something with my function? – HarryNC Sep 02 '22 at 14:03
  • are you still getting the same error or different this time? – Divyani Yadav Sep 05 '22 at 13:20
  • Hi @DivyaniYadav, thanks for checking in. I was still getting the error, must be something to do with my function and modular v9. I'm trying to look for a different approach. All I want to do is submit a post from the UI that creates a document within firestore collection, saving the title and description of the form. User has to be signed in and I save the users ID in that document also. However I'm meeting so many challenges trying to do this. – HarryNC Sep 06 '22 at 10:47
  • @HarryNC, it seems that issue has been resolved now, i also have edited my answer, is it helpful? – Divyani Yadav Sep 14 '22 at 09:36