Cannot execute cloud functions in firebase emulator - firebase

I am trying to use the Firebase emulator to deploy my firebase flutter app, and everything works fine except when I call a method that calls a cloud function. I get an error [firebase_functions/unauthenticated] Unauthenticated and my cloud function doesn't execute(the rest of the method executes fine). I don't have this problem if I do it in production mode. At first I thought it was a security rules problem so I did:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
but still didn't work. I also tried this thread Newly Created Firebase Functions Throwing UNAUTHENTICATED Error and allowed all users to access the cloud functions but still didn't work. I don't know why is this happening in the emulator and not in production mode, and how to solve it. Help please.

The error was that I was not accesing the cloud functions from the emulator. I was accesing the real cloud functions from my production enviroment. I am working in flutter so I solved it by adding
FirebaseFunctions functions = FirebaseFunctions.instanceFor( region : "europe-west1");
functions.useFunctionsEmulator('localhost', 5001);
var delete = functions.httpsCallable(deleteShoppingListsCollectionsFunction).call(data);
Before that what I was doing was:
var delete = FirebaseFunctions
.instanceFor( region : "europe-west1")
.httpsCallable(deleteShoppingListsCollectionsFunction).call(data);

Related

Is it possible to assert the number of reads/writes in a Firebase Cloud Function test?

I have a test suite that runs integration tests for my Firebase Cloud Functions against a locally running Firebase emulator, is it possible to assert the number of reads/writes made to the emulated Firestore instance?
E.g. for the following function I would want to assert that 1 write occurs & 0 reads
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.addMessage = functions.https.onCall(async (data, context) => {
const original = data.query.text;
const snapshot = await admin.firestore().collection("/messages").add({ original: original });
return { code: 200, message: "Success" };
});
Currently, Its not possible to assert the number of reads and writes in a Firebase Cloud Function test.
I would suggest that the best way would be is to write the test data to the Firebase Emulator, then read it back and also count the number of collections/documents as well using Client SDK.
If you want to assert data coming from the Firebase Emulator, then you can use Requests Monitor. We used Client SDK for this purpose as Admin SDK requests and access calls will not be listed because it bypass Security Rules. It's a current limitation according to this Blog.
The Firebase emulator has a log that shows requests as shown in example below.
Note: I don't think that you should have a dependency on it, since Firebase Emulator Request Monitor is a new feature that its implementation may change and Admin SDK can be included over time.

How to trigger Pub/Sub Topic for Firebase Emulator

Using Firebase Functions, I have code that runs every hour via a Google Cloud Scheduler Job.
It looks like this:
exports.hourly_tick =
functions.pubsub.topic("hourly-tick").onPublish((message, context) => {
return getData()
.then((data) => {
sendEmail(data["message"]);
})
.catch((error) => {
return console.log("🚩 Caught error: ", error);
});
});
I need to be able to test this locally, and am able to start my Firebase Emulator via firebase emulators:start from my terminal. However I do not know how to trigger this function in my local test environment to see logs in the local emulator.
How can I test this scheduled job / firebase function with the local emulator?
This is an ongoing feature request in Firebase tools (see GitHub issue).
As mentioned in the thread:
I think we maybe misled with how we represented #2011. It lets those functions be loaded into the emulator but doesn't actually trigger them on a schedule. Instead you'd have to manually trigger them using a Pub/Sub message.
You can check a workaround on this answer where you'd have to manually trigger a scheduled function using a Pub/Sub message.

Deploying Cloud Firestore Trigger function from GCP Console

I have a function that is fired on a onUpdate trigger from my cloud firestore database.
The function not being called at all when I change my database.
I did not deploy the function using firestore CLI, instead I deployed it using the GCP Console.
Here is the function:
exports.NotificationListener = functions
.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const userId = context.params.userId.toString();
const eventId = context.eventId;
console.log('EventId:' + eventId);
console.log('Change in:' + userId);
return 200;
});
Here is the deployment information from the GCP console (showing the trigger):
Finally, here is the Cloud Firestore schema:
I want to monitor any changes to any "USER" in the collection: "/user", hence I am using "user/{userId}".
Why is this function not being called when I change the database ?
EDIT 1
A little information about my environment:
I have my entire project core in a TypeScript file. I have over 40 HTTPS triggered functions that are currently online.
I add a new function in my TS file, then I do a npm run build to compile and get the JS file.
Finally, I go to Google Cloud Console and create a function and choose "Zip Upload" and upload the compiled JS file (obviously, along with the required JSON files for getting Database URL, Authentication etc.)
This approach works perfectly fine, at least for HTTP triggered firestore functions.
Now I repeated the same steps as above for the onUpdate trigger and just instead of choosing HTTP trigger, I chose Cloud Firestore trigger. The trigger information can be found above in the screenshot.
onUpdate is not being fired on DB changes.
EDIT 2
My event trigger function NotificationListener is showing up in the firebase console functions list along with my other 40 HTTPS functions. But it is not being called.
#doug-stevenson, your answer seems to have disappeared, I am not sure why.
Anyway, I found the reason why it wasn't working.
My firebase database was in project "Placeholder 1" and my GCP functions were in project "Placeholder 2".
Now, I was able to update the "Placeholder 1" DB from GCP functions (in "Placeholder 2") using firabse-functions API because I set the DatabaseURL to "Placeholder 1".
But, just setting the DatabaseURL to the desired database doesn't work if you want to LISTEN to the database for changes. You actually need to have the function in the same project otherwise it is not able to subscribe and listen for events.
I think it's a little inconsistent that you can read/write to a DB from different projects, but to listen for events, function needs to be in same project.
Or maybe I am missing something fundamental that caused this confusion for me.

(firebase functions) Error: Forbidden Your client does not have permission to get URL /

I have problem when invoking deployed function in firebase. I have an editor role in the firebase project and when I deployed functions, didn't have any problem with invoking them. When I deployed a new function yesterday, I got the error message that says
Error: Forbidden
Your client does not have permission to get URL / < Function Name > from this server.
Nothing has been changed to my role. It is strange that since yesterday, whatever function I deployed, threw those errors.
In gcp console/cloud functions, where you can see permissions of the function that was selected, I've noticed that "cloud functions invoker" was not assigned to that function. I thought this should be added to any function by default as long as I have an editor access but strangely it does not add them anymore. other functions that were deployed since yesterday have the same issue
any suggestions or advices will be appreciated. Thank you
Please Review Allowing unauthenticated function invocation
As of January 15, 2020, HTTP functions require authentication by default. You can specify whether a function allows unauthenticated invocation at or after deployment.
So here's the answer from the firebase team
The issue you are experiencing is likely caused by the fact that after January 15, 2020, Google Cloud Functions automatically creates HTTP functions to be >private by default.
Please, update the CLI, by running the following command:
npm install -g firebase-tools
This will ensure that future HTTP functions that are created will be publicly accessible.
Lastly, for the existing functions that has the permission issues, you will need >to manually set a function to public using Cloud Console or gcloud CLI.
If you have any questions or you are still facing this issue, please, don’t >hesitate to write back.
edited*
There could be several reasons to cause this issue.
check your function endpoint url make sure there's no typo or space
In the gcp console, make sure you have permission to invoke function https://console.cloud.google.com/functions/list?project=<YOUR_PROJECT_ID>
If the above two are checked, delete your function and redeploy your them again
Unfortunately, you can't do this in Firebase, you have to go into the Google Cloud project which 'hosts' your firebase project. You can follow this guide by Google, and have a look at the screenshots below:
You should see Allow unauthenticated now
To allow unauthenticated invocation of a function, you add the special allUsers member id to the function and grant it the Cloud Functions Invoker role:
You can limit domain access in your function, for example:
exports.myTest= async(req, res) => {
res.set('Access-Control-Allow-Origin', 'foo.com');
...etc
I defined my Firebase cloud functions in typescript/JS and deploy using Firebase CLI. I got this error after customizing the deployment settings, and I fixed it by specifying invoker="public" - I did not need to dig into IAM settings or use the console or CLI to fix.
export const serve = functions
.region("us-west2")
.runWith({
invoker: "public", // this is the magic line
})
.https.onRequest(
async (request: functions.Request, response: functions.Response) => {
// ...
})
updating firebase-tools wasn't enough in my case because i already deployed that function and updating it didn't fix the issue, i had to delete it and deploy again

Unsupported Firebase Functions services?

I'm attempting to deploy a minimal Firebase Function based on an authentication trigger. I've worked successfully before with https and database triggers but I'm getting an error while deploying an authentication trigger (docs, reference).
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
exports.onCreateUser = functions
.region('europe-west1')
.auth.user()
.onCreate((user: admin.auth.UserRecord, context: functions.EventContext) => {
console.log(`Triggered On Create User: ${user.email}, ${user.uid}.`);
});
I receive the following error:
Ignoring trigger "onCreateUser" because the service "firebaseauth.googleapis.com" is not yet supported.
I've tried changing my engine node version from 10 to 8 or changing the region to europe-west2 or us-central1 but any variations on my configuration would throw this error.
The documentation I've referenced does not mention a limited support for these triggers. Is there any page with an overview of unsupported services and their limitations?
I seem to have mixed up my intent to run serve and deploy here. As I have been told by a very responsive support team the serve script spins up the emulator and is currently limited to the following scopes:
Functions
Firestore
Realtime Database
Hosting
For the development phase, however, you can make use of the interactive shell:
$ firebase functions:shell
✔  functions: Emulator started at http://localhost:5001
i  functions: Loaded functions: onCreateUser
firebase > onCreateUser({"uid":"99999","email":"test#testing.com"})
'Successfully invoked function.'
>  Triggered On Create User: test#testing.com, 99999.
>  Function returned undefined, expected Promise or value

Resources