I have been struggling to get a simple firebase callable function to work - I was constantly getting CORS errors:
"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."
This is the code:
import * as functions from 'firebase-functions';
export const sayHello = functions.https.onCall(() => {
return {
message: "Hello world"
};
})
it is called using this code:
const sayHello = firebase.functions().httpsCallable('sayHello');
sayHello().then((result) => {
console.log(res.data.message)
})
I came across this post:
CORS error on httpsCallable firebase in Create React App
The answer given is:
"The Cause:
Cloud functions were forbidding access to the function. Newly created functions did not have a Cloud Functions Invoker. This change was implemented on Jan 15, 2020
Solution:
Create Cloud Functions Invoker and set to allUsers. https://cloud.google.com/functions/docs/securing/managing-access-iam".
This worked for me with permission set to allUsers and role set to Cloud Functions Invoker.
I noticed that there is also an allAuthenticatedUsers role. It doesn't work if this is set to Cloud Functions Invoker or Cloud Functions Admin.
What does allAuthenticatedUsers mean? Does this mean that within my webapp a user has to sign in app.auth().signInWithEmailAndPassword or similar mechanism? This doesn't seem to work.
Related
This question already has answers here:
Firebase Cloud Functions Firestore Trigger produces: Error: 7 PERMISSION_DENIED: Missing or insufficient permissions
(9 answers)
Closed 10 months ago.
I'm attempting to use Google Cloud Functions to interact with a Google Firestore collection. Going through the documentation, it seems like the suggested library to use is: https://www.npmjs.com/package/#google-cloud/firestore
the documentation on the library indicates it should only be used in a secure environment (like Cloud Functions) and that it would take advantage of ADC ( Application Default Credentials ). However when I implement it in a cloud function I'm getting the following response from the library call to firestore.get()
{
"code": 7,
"details": "Missing or insufficient permissions.",
"metadata": {}
}
For the sake of this article lets say the project id is "mobile-site"
I made a firestore collection:
"site"
which has a single document:
{
"hi": "there"
}
and a cloud function to call which attempts to get the document:
const firestore_1 = require("#google-cloud/firestore");
const projectId = 'mobile-site';
const firestore = new firestore_1.Firestore({ projectId });
/**
* Responds to any HTTP request.
*
* #param {!express:Request} req HTTP request context.
* #param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
return TestStuff().then(v => {
return res.status(200).send(v);
}).catch(reason => {
return res.status(500).send(reason)
})
};
//
function TestStuff() {
const collection = firestore.collection('site');
return collection.get().then(query => {
// this code is never invoked
return {query, version: '1.0.1'}
});
}
As a troubleshooting step, I did the exact same thing above on a personal account, and everything works swimmingly. So its just my company's enterprise solution that causes an issue.
Before you say "check the Firestore Security Rules", this sdk circumvents the firestore rules since its in network and attached to a service account. Speaking of which, here is the service account role/permissions, I've added quite a few in an effort to resolve the issue, so some may be completely unrelated, will use an example name:
IAM & Admin
example-service-account#appspot.gserviceaccount.com
Editor
Service Account User
Viewer
Cloud Functions
example-service-account#appspot.gserviceaccount.com
Cloud Functions Admin
Cloud Functions Invoker
Cloud Functions Service Agent
Editor
Firebase Admin
Any help or suggestions to resolve or troubleshoot further are appreciated.
Turns out the issue is there are multiple IAM "principal" role assignment areas.
Previously I had verified the service account settings here:
https://console.cloud.google.com/
Menu > IAM & ADMIN > Service Accounts > ( Clicking on the default service account ) > Permissions
However the location that resolved the issue for me was found here:
https://console.cloud.google.com/
Menu > IAM & ADMIN > IAM
In my case the service account in question wasn't even present, so it had to be added. My administrators attached the following roles:
Firebase Admin SDK Administrator Service Agent
Service Account Token Creator
And now the functions work
User "Marc Anthony B" pointed me to
Firebase Cloud Functions Firestore Trigger produces: Error: 7 PERMISSION_DENIED: Missing or insufficient permissions
which was extremely close but not exactly the same since I am using a different library and the Role assignment is different.
I have a Firebase function to do some data processing, and I only want to invoke it through Google Cloud Console manually.
Just a simple function like this (using node.js):
import * as functions from 'firebase-functions'
// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
export const test = functions.https.onRequest(async (req, res) => {
res.send({
query: req.query,
body: req.body,
})
})
The way I did it is to deploy the function via the firebase-cli then remove the Cloud Function Invoker role in the permission tab from GUI.
It seems to work.
But I noticed one thing, when I send the request with Postman
when you send a GET, the error is 400,
But for any request that's not a GET, you get a proper 403
My questions are:
why GET is 400 while the others are 403?
am i doing it right in terms of my requirement?
what's the correct way of doing it?
does the function get invoked while sending a request like POST?
I am using functions and hosting from firebase.
I have defined one function as shown below.
const functions = require("firebase-functions")
const cors = require('cors')
exports.hello = functions.https.onRequest((request, response) => {
functions.logger.info("Hello logs!", {structuredData: true})
return cors()(request, response, () => {
response.send({data: 'hello fire functions'})
})
})
And in hosting call the function like this:
import firebase from "firebase/app"
import "firebase/functions"
const config = { ... }
firebase.initializeApp( config )
const test = firebase.functions().httpsCallable('hello')
test().then( result => console.log(result) )
Then the functions log will be written twice as follows:
2:37:07.548 PM hello: Function execution started
2:37:07.599 PM hello: Hello logs!
2:37:07.600 PM hello: Function execution took 53 ms, finished with status code: 204
2:37:07.809 PM hello: Function execution started
2:37:07.816 PM hello: Hello logs!
2:37:07.817 PM hello: Function execution took 8 ms, finished with status code: 200
It is also displayed twice in the usage graph.
This behavior means I have to pay twice as much usage. This is not normal.
If cors is not used, the log and usage graph will show that it has been executed only once.
But if you don't use cors: When you call a function in the browser, the function is executed, but the browser gets a CORS error.
How can I solve this problem? I couldn't find a solution in the official documentation. (This is a problem after hosting and functions deploying. It is not a localhost environment.)
Firstly, you are mixing up HTTP requests on the client with callable functions. That's not what you're supposed to do. Please review the documentation for both HTTP functions and callable functions to see how they are different. If you're using the callable SDK on the client, you should use a callable function on the backend.
Second, this is the normal expected behavior. Callable functions use CORS between the client and server. CORS clients issue a preflight request which causes the first request and first log. Then, the actual request which causes the second request and second log. You cannot avoid this when using CORS - that's simply how the protocol works.
See also:
Firebase Cloud Function executing twice when triggered over HTTP
Enabling CORS in Cloud Functions for Firebase
Cloud Functions for Firebase triggering function on CORS preflight request
If you're using Firebase Hosting, you probably don't need CORS.
You can avoid preflight requests by adding rewrites to firebase.json.
However, there are conditions such as the position of the function must be us-central1.
https://firebase.google.com/docs/hosting/functions
I have been using firebase functions for quite some time and all deployments of functions have been going quite smoothly. All of a sudden any new functions deployed have stopped working and any calls from the client return a CORS error. If I check the functions list in the firebase dashboard I can't see the functions being called which is similar to what I would expect if the functions simply didn't exist at all.
I am now just trying a simple basic function like below:
exports.createSession = functions.region('europe-west2').https.onCall(async (data, context) => {
return ({status: 200})
});
On the frontend I am doing a simple call like below:
const createSessionFunction = functions.httpsCallable('createSession');
const response = await createSessionFunction({});
All the other functions that were create and deployed prior to this week are working fine. Any new functions are not.
The error I get is below:
Access to fetch at 'https://europe-west2-xxxxxxx.cloudfunctions.net/createSession' 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.
index.cjs.js:614 POST https://europe-west2-xxxxxxxz.cloudfunctions.net/createSession net::ERR_FAILED
My function list on the firebase GUI show this function does exist:
createSession - Request - https://europe-west2-xxxxxxxx.cloudfunctions.net/createSession-europe-west2-Node.js 8 -256 MB - 60s
However the logs show that it is never called from the client when I'm trying to test it which means the client might not be detecting this function at all.
I have tried the following steps with no luck:
Delete and redeploy the functions
Rename the function and redeploy
Deploy the same new function on different applications (dev/test etc)
Any ideas?
This was resolved on the google cloud dashboard by granting all my functions public access. The default permissions has changed from public to private.
https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation
This question already has answers here:
How to resolve 'preflight is invalid (redirect)' or 'redirect is not allowed for a preflight request'
(6 answers)
Closed 2 years ago.
server code
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.hello = functions.https.onCall((data, context) => {
console.log(data.text);
return 123;
});
client code
const myFunc = firebase.functions().httpsCallable('hello');
myFunc({text: 'world'}).then((rslt)=>{
console.log('rslt:', rslt);
});
But it is not work.
I got error message at client browser console.
Access to fetch at 'https:// ==skip== /hello' from origin
'http://localhost:5000' has been blocked by CORS policy: Response to
preflight request doesn't pass access control check: Redirect is not
allowed for a preflight request.
How can I solve this problem?
I did not find a solution in the google guide documentation.
I see comments and add content.
The query does not arrive at the server.
If I try after functions deploy it works fine.
But it doesn't show up on the local console, but on the firebase console.
How can I make a local server call?
It's crazy to deploy every time you test a function.
Hard to tell from the given code why your request violates Cross-Origin Resource Sharing. Take a read on this matter and figure out what is it that you include (whether by intention or not) in your HTTP request that causes it. Headers maybe?
In the meantime, you can enable CORS in Firebase Functions with require("cors"):
const cors = require("cors")({origin: true});
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.hello = functions.https.onCall((data, context) => {
cors(data, context, () => {
console.log(data.text);
res.send("123");
}
});
Regarding local testing of Firebase Functions, you can do so by using this command:
firebase serve --only functions
Local testing of Firebase Hosting / Functions
Enabling CORS in Firebase Functions.