skip to Main Content

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?

2

Answers


  1. Chosen as BEST ANSWER

    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.


  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search