80

I'm trying to call a callable Cloud Function from my app, but I'm facing CORS issues. enter image description here

I can't enable Cors since I don't have access to the request and response on the onCall function. This is my function:

exports.UserInvitation = functions.https.onCall((data, context) => {
  const email = data.email


  return new Promise((resolve, reject) => {
    admin.auth().createUser({
      email: email,
      emailVerified: false,
      password: password
    }).then(resolve).catch((err) => {
      console.error(err.code)
      reject(new functions.https.HttpsError(err.code, err.message))
    })
  })
})

And this is how I call it:

functions.httpsCallable('UserInvitation')({ email: this.input.value }).then((data) => {
      console.log('Sent invitation:', data)
})

Firebase-functions package.json:

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "dependencies": {
    "bluebird": "^3.5.1",
    "firebase-admin": "~5.12.0",
    "firebase-functions": "^1.0.1"
  },
  "private": true
}

WEB SDK Firebase version: 4.13.1

benomatis
  • 5,536
  • 7
  • 36
  • 59
Pietro Coelho
  • 1,894
  • 1
  • 26
  • 34
  • 14
    CORS should be automatically handled by the onCall handler. I suspect that the error message about CORS is inaccurate, and a result of the function returning 500 internal. What do you see in the Functions Logs in the Firebase Console? – bklimt May 10 '18 at 18:58
  • 1
    You're right, the problem is with my error handler. The documentation says I can reject a promise with a instance of functions.https.HttpsError, but even though I'm doing that I'm getting a 500 error on the client. How can I fix that? – Pietro Coelho May 11 '18 at 18:18
  • Even if I remove my return statement and add a `throw new functions.https.HttpsError('test/code', 'error message')` it only returns a object with message and status equals to "INTERNAL" – Pietro Coelho May 11 '18 at 18:21
  • Ah yes, the status code passed to HttpsError cannot be `test/code`. It must be one of the standard codes listed here: https://firebase.google.com/docs/reference/functions/functions.https.HttpsError – bklimt May 11 '18 at 22:54
  • 1
    @bklimt please create an answer with this comment and I'll accept it :) I believe this detail should be added to the firebase onCall documentation – Pietro Coelho May 14 '18 at 17:57
  • The HttpsError codes page has moved. https://firebase.google.com/docs/reference/js/firebase.functions#functionserrorcode – akauppi Jun 19 '20 at 23:16

26 Answers26

91

For anybody else who has arrived here searching firebase callable functions cors errors, here's my checklist:

  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. That was not the case.
  5. This last point is easy to oversee as everything else in the Firebase universe is more or less plug-and-play, but you need to make sure your functions are accessible by giving them the right permission. (This point is taken from @kitson's answer below. As many only read the first answer I think it is important to highlight this.)

Deploying a callable function to a specific region:

// This is the file in which you define your callable function.
const functions = require('firebase-functions');
...
exports.yourFunc = functions.region('europe-west2').https.onCall(async (data, context) => {
    ...
})

Calling a function in a specific region from the client (in this case, a vuejs web app):

// In my case, this is a vuex store file, but it is safe to assume this is plain old javascript
import firebase from 'firebase/app'
import 'firebase/functions'
...
firebase.app().functions('europe-west2').httpsCallable('yourFunc')

Note: firebase.app().function... vs firebase.app.function...

allegutta
  • 5,626
  • 10
  • 38
  • 56
Aido
  • 1,090
  • 8
  • 8
  • 14
    This made it for me! Didn't have region in the calling. – akauppi Jun 19 '20 at 23:43
  • 8
    Basic checklist... you saved me with "Ensure the function name is correct" – Séraphin Aug 01 '20 at 03:10
  • 1
    Reference for Angular: https://github.com/angular/angularfire/blob/master/docs/functions/functions.md – tmorell Feb 14 '21 at 15:29
  • 1
    The cors issue comes because when trying to call a non-existent function redirects you to Google's signin, which has cors enabled ofc – CiriousJoker Mar 19 '22 at 00:00
  • This just leaves it again with allUsers invoker which allows for Unauthorized access. People saying it's working again after redeploy is just because the recreated functions has allUsers invoker.. – Street0 Apr 02 '22 at 10:54
  • Thanks, I spelled the name incorrectly. This checklist saves me. But I can't believe that incorrect function returns CORS. It should be return message just like "There is no function named `recalucatY`". – Khaschuluu Munkhbayar Oct 17 '22 at 06:58
  • I want to cry... Hours and my issue turned out to be no 2. Even tried emulators etc. I need more coffee. – Werner7 Mar 10 '23 at 00:29
  • And one more clarification to the function name point - I would recommend not using hyphens or underscores in function names as they get swapped in URL's which seems to trigger CORS in production on Web. Switching to camelCase names finally solved the issue for me – Pjotr Gainullin Jun 06 '23 at 09:37
44

For anyone looking at this post Jan 2020..

Found this answer on Reddit (https://www.reddit.com/r/reactjs/comments/fsw405/firebase_cloud_functions_cors_policy_error/)

Turns out on 15th Jan 2020, Google changed the security settings where all new functions no longer have a Cloud Functions Invoker. This means that all newly created functions will have their access forbidden, thus resulting in a CORS policy block.

Here is how you fix it, as it's not all that obvious:

https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation

Kitson
  • 1,153
  • 9
  • 22
  • 2
    Good lord. What a mess of a bug to find. Thank you! – moto Apr 26 '20 at 05:54
  • but this will allow all users to call this function I mean I have done that CORS error gone but now I can trigger that function from postman with out any headers!! is this the only way @Kitson – Kishan Oza May 13 '20 at 18:51
  • 2
    I was using `.https.onCall(async (data, context) => { ... })` and the context has access to teh auth user `context.auth`. I was then using this to check permissions and throw an error for unauthenticated users. – Kitson May 15 '20 at 15:14
  • 9
    This is infuriating - for such a big company the docs are all over the place on this topic. How was that not all over the place when it happened? Thank you. – Eric Crescioni Feb 04 '21 at 23:33
  • 1
    Thanks, this worked for me. Interesting tidbit to add is that I deployed 3 functions at the same time and only 1 had this issue. – dvdmmc Mar 11 '21 at 18:22
  • So yeah, I just spent the last 36 hours banging my head against this. Thank you. – Ryan Prentiss Aug 08 '21 at 04:40
  • This shouldn't be a solution. allUsers leaves it open to Unauthorized access. Answer should consider restricting access to authorized users and consider registering some domain / origin to allow access. Not this – Street0 Apr 02 '22 at 10:53
27

I had this problem with some of my Firebase functions but not others. I eventually fixed it by doing this:

  1. Commenting the function out in index.js
  2. Running firebase deploy
  3. Entering y at the prompt to delete the function
  4. Waiting for 5 to 10 minutes
  5. Removing the comments around the function and running firebase deploy again

Without any changes to the function itself, it now runs without any CORS issues.

iStuart
  • 413
  • 4
  • 6
  • 2
    Unbelievable, after spending several hours trying all the different solutions here, I deleted every function and redeployed them again and suddenly, they started working without any CORS issues. During that time I was still unsure whether I would also have to do @Nikita's solution for `https.onCall(..)` functions where the user is authenticated (because nothing made them work). Answer is no - complete deletion and redeploy fixed the issue. – sceee Apr 13 '21 at 15:08
  • I tried every single thing in this thread. But this one was the solution for me. Just delete all cloud functions once. Then redeploy and it works again! – mesqueeb May 15 '21 at 08:01
  • 2
    I did something extremely similar: deployed THE EXACT SAME FUNCTION with a different name: great success. Flipped a table and moved on. – Félix Paradis Jun 02 '21 at 16:44
  • 1
    I tried all kinds of solutions and yes, the solution was the same for me, just remove all the functions and deploy them again. What the actual.. I've been sitting with this error for hours wondering what and how to solve the issue and then it is just "delete and try again"... feel so stupid. – 今際のアリス Jun 16 '21 at 16:05
  • I tried every other possible solution ... No offense but I tought this never gonna work because of that I even never tried that but man ... I can say this was the issue. Thank you ! – Suat Karabacak Aug 14 '21 at 11:29
  • I will also add my misery to this pile. Deleting the function from the console and re-deploying it was enough to get the functions working. – Eosis Feb 04 '22 at 12:30
  • I vote for this solution. You saved my day man... Thanks – Chrisk8er Feb 05 '22 at 03:10
  • Deploying to another region, then redeploying to the correct region seems to produce this. Deleting the function in the webAPI and redeploying did the trick. Thanks! – Witt Feb 22 '22 at 13:48
  • This worked, and it makes me sad. In case Google can't find this: this is the fix to CORS errors for onCall firebase functions running into preflight check errors due to a suspected region error in GCP. – Mentor Mar 15 '22 at 15:01
  • I'm going to have to start trying this kind of solution earlier on in the troubleshooting process... deploying under a new name fixed it. – Jeroen van de Ven Apr 14 '22 at 11:38
  • Deleted all functions and redeployed.... FIXED. Thank you ..! – Ryan Sep 26 '22 at 00:31
  • This fixed it for me. Completely crazy that we have to do this. – Allen Nov 19 '22 at 12:23
  • Yes, still a good solution in Dec 2022. For me I had deployed in an environment with a spotty internet connection, and there were various issues updating the function too. Deleting and recreating - even without any changes - solved it all. – HughHughTeotl Dec 05 '22 at 13:45
  • This has happened to me twice and it's still unbelievable that Firebase, a product designed explicitly to improve the dev experience, still has countless different errors that result in a "CORS error" that's not really a CORS error. – jvhang Mar 21 '23 at 23:51
7

For those facing this error after enabling firebase on an existing GCloud project, there is some complexity which is not taken care of automatically as it would be if it were just a firebase app.

I had this specific problem because I wanted my firebase function to be publicly accessible, but you have to specifically configure this if you're using google's Cloud Functions.

Here are the steps to fix:

  1. Go to the cloud function tab
  2. Select your cloud function (check box)
  3. Click "Add members" under Permissions tab in the right side
  4. Enter "allUsers"
  5. under "New memebers" Select Role as "Cloud Functions -> "Cloud Functions Invoker"
  6. Save
  7. Test your cloud function by just pasting it in the browser

Cheers

Nikita Jerschow
  • 836
  • 2
  • 11
  • 24
  • Step 5 is important! Before I use other role and do not works. Thanks! – Jonatas Eduardo Dec 04 '22 at 19:22
  • You can also achieve this using the gcloud CLI tool: ```gcloud functions add-iam-policy-binding yourFunctionName --region=us-central1 --member=allUsers --role=roles/cloudfunctions.invoker``` – Kurt Aug 30 '23 at 11:47
7

Probably many will hit this issue with the emulator and cors messages.

I havn't seen my case discussed in any discussion I've seen in Google, I do have seen many "can't reproduce", maybe my case will shed some light:

In my case the issue was that I wasn't running the hosting from the firebase emulator.

When you run your react app via npm start - while the functions run via firebase emulators:start, you will see the Cors errors.

So when testing cloud function calls, rather using npm start, you should do npm run build and then access the app from the emulator...

Search for something like: "hosting: Local server: http://localhost:5000"

few notes -

  • Your functions should also work against the emulator via

const functions = firebaseApp.functions('europe-west3');// lets assume thats your region functions.useFunctionsEmulator('http://localhost:5000');

  • While the note on using function emulator (with the region) is crucial I do not think the rest of the answer still holds true. I managed to get the onCall functions working running the app itself outside of the emulator. – Krzysztof Krzeszewski Aug 11 '22 at 07:33
6

My issue was not with CORS, but with my error handler. Instead of rejecting the promise, I've used throw directly in the catch handler.

catch((err) => {
  throw new functions.https.HttpsError('unknown', err.message, err)
})
Pietro Coelho
  • 1,894
  • 1
  • 26
  • 34
  • that seems extremely weird to me. Rejecting inside a promise that you are returning in the cloud function, feels to me like it's the exact same thing as throwing... – mesqueeb Mar 29 '20 at 01:23
6

For me, I had to allow access to allUsers for the function.

  1. Go to Google Cloud Platform Console Cloud Functions. You can click on the Detailed usage stats in the Functions tab on Firebase Console enter image description here

  2. Go to the Permissions tab

  3. Click Add

  4. Add appropriate permission enter image description here

Bao Pham
  • 577
  • 7
  • 11
  • Thanks! This helped me actually "see" what the issue was. Deleting and redeploying worked, but this is how I knew it was broken. – Jed Grant May 25 '23 at 17:26
6

I just had the error when using the v2 cloud functions with the web sdk 9.12.

The solution for me was to not use the function name but the complete url of the v2 callable cloud function.

import { getFunctions, httpsCallableFromURL } from 'firebase/functions';

const functions = getFunctions();
const addMessage = httpsCallableFromURL(
  functions,
  // the URL of the function
  "https://addmessage-xyz1234-uc.a.run.app/addMessage"
);

addMessage({ text: messageText })
  .then((result) => {
    // Read result of the Cloud Function.
    const data = result.data;
    const sanitizedMessage = data.text;
  });

Snippets taken from the docs: https://firebase.google.com/docs/functions/beta/callable#web-version-9_2

Mark Breuß
  • 61
  • 1
  • 1
4

If none of the above is helping: In my case the reason was that I havent correctly set up my regions. This can especially happen when using 3rd party libraries.

EDIT

To globally setup region, create a custom module exporting functions with regions setup and use this throughout the project:

// functions.ts
import * as _functions from "firebase-functions";

export const functions = _functions.region("europe-west1");
Code Spirit
  • 3,992
  • 4
  • 23
  • 34
  • Where do you set the regions? I'm using one, but only in the calling: exports.myf = functions.region("europe-west3").https.onCall(...). Is there some other place I should touch? – akauppi Jun 19 '20 at 23:24
  • You can wrap it in your own module and use this instead of the original functions module so you only have to call region once. – Code Spirit Jun 21 '20 at 06:29
  • My problem was solved by @Aido's answer. Needed to also have the browser code tell Firebase which region to use. – akauppi Jun 21 '20 at 09:36
3

I had the same issue. My solution was to open my Firebase project in https://console.cloud.google.com and navigated to cloud functions page.

Look for your function name go to its permission page, and add new role "Cloud Functions Invoker" to "allUsers" member.

MoOp
  • 91
  • 1
  • 5
3

My "take" on the answers so far (plus my own personal experience) is that, for a Cloud function called by a javascript webapp, pretty much anything that goes wrong with the function will throw a CORS error. But one particular cause of error will be hosting the function in one region and calling it from another. Here's some code you can use in a webapp to set this unambiguously so that you're not confused by the Firebase default (which, in any case, may not generally be appropriate).

import { initializeApp } from 'firebase/app';
import { getFunctions, httpsCallable } from 'firebase/functions';

const app = initializeApp(firebaseConfig);

const functions = getFunctions(app, '_my-region_');
const _my_function-name_= httpsCallable(functions, '_my-function-name_');

The function itself is then launched like this

_my-function-name_().then(response => console.log(response))

my-function-name must return a promise, eg:

exports.helloNewWorld = functions.region('europe-west2').https.onCall((data, context) => {
    const myPromise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("foo");
        }, 300);
    });
    return myPromise
});

Google's background docs on all this are at https://firebase.google.com/docs/functions/callable#web-version-9 and https://firebase.google.com/docs/reference/js/functions#getfunctions

MartinJ
  • 333
  • 2
  • 13
  • 1
    It worked for me if I m returning a promise from onCall, providing region is not required in cloud function as well as in client side code. – coure2011 Dec 07 '22 at 06:08
  • 1
    Yes, need a promise! Sometimes if there is some error inside the method even then its showing CORS, the key is to always first check the logs of cloud functions – coure2011 Dec 08 '22 at 09:41
2

I previously had deployed my function as an HTTP function (https.onRequest), then switched to a callable function (https.onCall). Firebase did not recognize this change.

I solved the problem by removing the function and deploying without it, then putting the function back in and deploying again.

steventilator
  • 205
  • 2
  • 8
2

If you are using multiple environments (Firebase Projects) to separate development and production (i.e Project-dev, Project-prod), make sure you have switch to the desirable environment. In my case, running this worked:

firebase use default
Wilson
  • 51
  • 1
  • 2
  • thanks that worked after I started my local emulator again. But do you also know why? What does the firebase environment have to do with my local emulator? – Ruben Dec 15 '21 at 22:45
2

Edit: This is no longer needed. Set up your v2 function same way as v1


For anyone using gen2 firebase functions, callable functions need to be initialized differently.

Until Cloud Functions (2nd gen) supports cloudfunctions.net URLs, you will have to use a different initializer in your client code. Rather than providing a function name, provide a full URL to the client SDK. The URL for your function is printed at the end of a successful firebase deploy command:

https://firebase.google.com/docs/functions/beta/callable

E. Sun
  • 1,093
  • 9
  • 15
1

In my case, it was just an "undefined" value passed thru the httpsCallable ... I have lost 3 hours because of the damn CORS error message ... that has absolutely nothing to do with the CORS ! I understand it's my fault for the undefined var, but I remember now I had the same issue 2 or 3 years ago. Please Google, fix this wrong error message !

Fox5150
  • 2,180
  • 22
  • 24
1

Helped in my case:

  1. Go to Google Cloud console
  2. Click the checkbox next to the receiving function. (Don't click on the function itself.)
  3. Click Permissions at the top of the screen. The Permissions panel opens.
  4. Find "allUsers" principal and remove access for it.
  5. Click Add principal.
  6. In the New principals field, type allUsers.
  7. Select the role Cloud Functions > Cloud Functions Invoker from the Select a role drop-down menu.
  8. In response to the dialog, click Allow public access.
  • 1
    Thanks for this refreshing reminder that the deployment process baked in firebase deploy will at times, fail. My new function didn't have the right permissions attached. – Stf_F Aug 17 '23 at 12:34
1

So my functions were working fine. Then I made some changes to the function file to tidy things up. I separated them into seperate files, functions based on specific domains. like this:

exports.domainA = require('./domainA/index');
exports.domainB = require('./domainB/index');
exports.domainC = require('./domainC/index');

All of my functions stopped working and I was getting the CORS error.

The functions worked when testing form the GCP console though, so I knew that the code was fine

Answer:

Turns out, When you seperate the functions, they are deployed as a group. When you call the function it should be prefixed with the group name like this:

var fn = firebase.app().functions("region").httpsCallable("domainA-<function-name>")

Note, that both function and the group name is case-sensitive.

NB. this only applies to callable functions, NOT onRequest functions

Hope this helps

0
  1. Errors should be as given in https://firebase.google.com/docs/reference/functions/functions.https.HttpsError
  2. I deployed callable function after changed function name and it's working.
BHAR4T
  • 338
  • 3
  • 14
0

I got the same error when I tried to create a custom token for signing in a firebase user. I have attached my code below. However, I later discovered that the issue was due to attempting to create multiple tokens, by calling the function several times with the same parameters.

export const getCustomToken = functions.https.onCall((params: any) => {
 return admin.auth().createCustomToken(params).then((token) => {
   return token;
  }).catch((error) => {
    console.log(error);
    return null;
  });
 });

SOLUTION
I solved the issue by first checking that the user is logged out before attempting to sign in. So I suggest that you first check if the user your trying to create already exists. I know this is a bit late but I hope this helps some one else.

this.fireAuth.currentUser.then((signedInAlready) => {
  if (signedInAlready) {
    return this.fireAuth.signOut().then(() => getCustomToken());
  } else {
    return getCustomToken();
  }
});

In your firebase functions you can check for an existing user as follows:

admin.auth().getUserByEmail('your-email').then((userExists) => {
if (userExists) {
  // return user
} else {
  // create a new user
}});
A Johnson
  • 1
  • 2
0

Basically, I did everything mentioned in tones of pages and answers regarding CORS error for onCall cloud functions, from changing the region or manually adding the invoke permission to more obvious ones, nothing worked for me. Just turned the onCall onto OnRequest and it works.

0

Permissions hiccup at the function level in my case too. All my callable functions were working fine, but one. Looking into their privileges in GCP, the working ones had a 'allUsers' principal with a 'Cloud Functions Invoker' role' set, but not the culprit. Updated that and everything is now working.

Stf_F
  • 846
  • 9
  • 23
0

For me the function name was wrong, but it wasn't obvious (to me ‍♂️). I use my index as an entry point and export all my functions from other files.

/index.ts

exports.auth = require("./exported-functions/auth");

/exported-functions/auth.ts

exports.validateUserEmail = functions.https.onCall(async (data) => {
  return await verifyUserEmail(data.email);
});

This makes the function name auth-validateUserEmail not validateUserEmail

I changes this:

const validateUserEmail = httpsCallable(functions, 'validateUserEmail')

To this:

const validateUserEmail = httpsCallable(functions, 'auth-validateUserEmail')

And BINGO it worked.

Kind of obvious now and I already knew this about function naming - but just in case it helps someone else.

0

I just had this issue.

I made sure the function name was correct. I made sure the function did not throw any errors. The function worked fine on a local emulator. I am using us-central1 so no need to specify a region.

What happened was the function previously deployed threw an error that resulted in a Cors error on the client. Redeploying the function still results in a Cors error. I deleted the function through the Firebase console, waited a few minutes, and redeployed the function, and it worked!

Hope this helps.

Kevin
  • 1
0

I found 2 solutions for when developing locally using functions emulator:

  1. @Mark Breuß's and @E. Sun's answers (use httpsCallableFromUrl instead of httpsCallable to make the call) OR

  2. set the v2 function's region to us-central1, regardless of what your default region is

galki
  • 8,149
  • 7
  • 50
  • 62
-1

i try every thing - nothing work.

  1. delete all function - not work...
  2. set the cors header - you cant do it in callable function
  3. add the "Cloud Functions Invoker" permission - it was allredy set..
  4. add try catch -didnt help

till i found someone that tald to change the rewrite rules in angular.json only this work for me here is the complete guide from firestore docs - pay attantion - it works only from region us-central1

how to solve CORS on firestore onCall function with context

anoter docs on CORs problem in callable functions

my lib versions

angualr 13

"@angular/fire": "^7.2.0",

"firebase": "^9.4.0",
yehonatan yehezkel
  • 1,116
  • 18
  • 28
-2

What worked for me was to remove the region params in my cloud function and then redeploy.

From functions.region("europe-west2").https.onCall(async (data) => {..

to functions.https.onCall(async (data) => {..