No auth information for emulated local Cloud function - firebase

I have the following setup: Vue Webapp with Hosting, Cloud Functions and Firestore.
When deploying the app to the Google Cloud, everything works. When i emulate the functions and hosting using firebase emulators:start --only functions,hosting, I can use the hosted app and cloud functions, but the authentication information from context.auth is undefined.
This works in the cloud but not in the emulator. Any ideas or solutions?
Note: I also set the admin credentials as described in the Docs.
Edit: I have a colleague that runs the emulator on windows successfully including authentication info, but I can't find any differences in the setup?!
export default class AuthGuard {
private readonly authentication: object;
public constructor(context: any) {
this.authentication = context.auth;
}
public isAuthenticated(): boolean {
console.log('this.authentication', this.authentication ); // this in undefined
if (this.authentication === undefined) {
throw new functions.https.HttpsError(
'unauthenticated',
'The request requires user authentication',
);
}
return true;
}

[Firebaser here] This is a bug in the emulators and it was fixed in version 7.16.2:
https://github.com/firebase/firebase-tools/releases/tag/v7.16.2
To update, just re-install the Firebase CLI at the latest version.

As mentioned in the official documentation Set up admin credentials in Emulator, this is an optional setting that you need to configure, in case you want to test your authentication as well.
To set up the authentication, please, follow the below steps.
Open the Service Accounts pane of the Google Cloud Console.
Make sure that App Engine default service account is selected, and use the options menu at right to select Create key.
When prompted, select JSON for the key type, and click Create.
Set your Google default credentials to point to the downloaded key:
As per the documentation indicates, this should be good for testing, since now it will be using the Admin SDK for tests. One of the examples mentioned is calling the function admin.auth().getUserByEmail(email).
Besides that, in this other below case - now from a Github issue - you can get more examples and information on how to use authentication in local emulator.
Add firebase authentication emulator to emulator suite
I would like to add as well, that as per the official documentation indicates, the Local Emulator is in Beta. So, it might be worth it to contact the Firebase support team directly, via their free support.
Let me know if the information helped you!

Related

firebase-admin, is it contradicting to use default credentials and serviceAccountId in same initialization?

I initialize firebase-admin like so for firebase functions:
const admin = require('firebase-admin')
const { applicationDefault } = require('firebase-admin/app')
admin.initializeApp({
credential: applicationDefault(),
serviceAccountId: 'firebase-adminsdk-hash#project-id.iam.gserviceaccount.com',
})
I had to add the serviceAccountId so that I could access another IAM permission. But I'm not sure if it's now unnecessary use applicationDefault() as well. Does anyone know if this is considered redundant / contradicting?
The short answer, in my opinion, would be: yes, it is redundant and inconsistent to specify the applicationDefault parameter as it is implicitly populated from the FIREBASE_CONFIG environment variable as explained in this previous question. (Please be aware the initialization can be different depending on the environment).
Here is a comparison from initializing the service account and the Cloud Functions together and impersonating the service account.
To get a more detailed explanation, we will need to dive into the documentation; we can see that the initializeApp() function has the AppOptions parameter (interface), where you can specify the serviceAccountId.
Finally, you can check all the functions from firebase-admin/app module, and get this description for the applicationDefault(httpAgent) function:
Returns a credential created from the Google Application Default Credentials that grants admin access to Firebase services. This credential can be used in the call to initializeApp().
Google Application Default Credentials are available on any Google infrastructure, such as Google App Engine and Google Compute Engine. See Initialize the SDK for more details.

How to get firebase App Check working with cloud firestore in a web app

I try to get App Check working in my vue.js pwa. Using the latest firebase sdk and by following steps here https://firebase.google.com/docs/app-check/web/recaptcha-provider
My api key (https://console.cloud.google.com/apis/credentials/key..) is not limited to any API restrictions. I did add some Application Restrictions on https tho including my project domains.
Everything works fine till i activate appCheck with recaptcha v3 and i get following console errors:
FirebaseError: [code=unknown]: Fetching auth token failed: AppCheck: Fetch server returned an HTTP error status. HTTP status: 403. (appCheck/fetch-status-error)
Further more the app can't get any firebase data or auth. I tried in several browsers and without any vpn stuff.
In my already installed pwa the App Check error occurs but connection to firebase still works..
Without App Check activated it both works without an issue. Also with an App Check debug token the whole thing just works. I don't understand why it breaks firebase connection even if i haven't enabled enforcement.
I appreciate any tips on how to solve this.
I found the problem i accidently left self.FIREBASE_APPCHECK_DEBUG_TOKEN = true; in my production code.
Remove this line or only use when in development envirement solved the whole problem
if (location.hostname === "localhost") {
self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
}
I didn't expect this line to impact browsers where i haven't registered a debug token to fail with the regular appCheck but of course it doesn't make sense to use it in production anyways.
Based on your question, you want to enable Firebase App Check for Firestore with Web Application. Currently, Firestore App Check does not support it.
As per this Documentation:
Cloud Firestore support is currently available only for Android and iOS clients. If your project has a web app, don't enable Cloud Firestore enforcement until web client support is available.
I'll leave an answer for people who have problems with the setup. For the more detailed answer, you can check this question.
In short, you need to do a few steps.
Set up a firebase.
Go to how to set up app check.
Register reCAPTCHA here and add the secret_key to the Firebase console, and the site_key to your web code.
Initialize the Firebase in your code based on how to set up app check docs.
Get your debug_key and add it to your firebase console and code.
Finally, the code should look something like this:
Don't forget to save your key to a .env file or firebase.js or somewhere where you won't upload it to git.
if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') {
window.FIREBASE_APPCHECK_DEBUG_TOKEN = 'your_debug_token';
}
const appCheck = initializeAppCheck(app, {
provider: new ReCaptchaV3Provider('your_site_key_from_register'),
// Optional argument. If true, the SDK automatically refreshes App Check
// tokens as needed.
isTokenAutoRefreshEnabled: true
});

How can I "admin.initializeApp();" no arguments in local

I am always grateful for your help.
I want to write code admin.initializeApp(); both locally and in production.
When I deploy functions to production with no auguments, it works.
But locally, it requires me to write it like below:
const serviceAccount = require("/home/yhirochick/development/ServiceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://xxxx.firebaseio.com/"
});
In the official documentation it says that configuration is applied automatically when you initialize the Firebase Admin SDK with no arguments
But when I execute the command firebase serve --only functions locally and some calls some requests by postman produce the error below:
[2019-07-22T06:45:26.227Z] #firebase/database: FIREBASE WARNING: Provided
authentication credentials for the app named "[DEFAULT]" are invalid. This
usually indicates your app was not initialized correctly. Make sure the
"credential" property provided to initializeApp() is authorized to access the
specified "databaseURL" and is from the correct project.
I want to know How can I "admin.initializeApp();" no arguments locally.
I have grappled with this also and I don't think the local testing scenario currently is explained very well in the official documentation. But here is a solution:
For your local environment you need to download the firebase projects firebase service account json file (found in firebase console under project settings -> service account) and set an environment variable GOOGLE_APPLICATION_CREDENTIALS to point to the file:
# Linux/MACOS version
export GOOGLE_APPLICATION_CREDENTIALS="[PATH_TO_YOUR_SERVICE_ACCOUNT_FILE]"
Read more here, also on how to do this on Windows
Now you will be able to use admin.initializeApp() (with no arguments) locally.
A possible downside of this approach is that you have to set the environment variable each time you fire up a terminal before you start the firebase emulator, because the variable gets deleted when you end the session.
Automate it...
You could automate the export ... command by bundling it together with the command that fires up the emulator. You could do this by adding an entry to the scripts section of your package.json, e.g.:
"local": "export GOOGLE_APPLICATION_CREDENTIALS='[PATH_TO_YOUR_SERVICE_ACCOUNT_FILE]' && firebase emulators:start --only functions"
Then, in this example, you would only need to type npm run local.
Alternative: provide explicit credentials in local environment only
Look at this example: https://stackoverflow.com/a/47517466/1269280.
It basically use a runtime node environment variable to separate between local and production and then use the explicit way of providing credentials in the local environment only.
This is my preferred way of doing things, as I think it is more portable. It allows me to put the service account file inside my codebase and not deal with its absolute file path.
If you do something like this then remember to to exclude the service account file from your repo! (it contains sensitive info).
Background: difference between production and local service account discovery
The reason that admin.initializeApp() (with no arguments) works out-of-the-box in production is that when you deploy to production, i.e. Firebase Functions, the code ends up in a 'Google managed environment'. In Google managed environments like Cloud Functions, Cloud Run, App Engine.. etc, the admin SDK has access to your applications default service account (the one you downloaded above) and will use that when no credentials are specified.
This is part of Google Clouds Application Default Credentials (ADC) strategy which also applies to firebase functions.
Now, your local environment is not a 'google managed environment' so it doesn't have access to the default service account credentials. To google cloud, your local box is just an external server trying to access your private Firebase ressources. So you need to provide your service account credentials in one of the ways described above.
Before I knew this, I thought that because I was already logged in to firebase via my terminal i.e. firebase login and were able to deploy code to firebase, the firebase emulator would also have the necessary credentials for the firebase admin sdk, but this is not the case.

firebase `signInWithEmailAndPassword` undefined

I'm a little new to firebase/cloud functions so forgive if I'm missing something simple.
I'm frustrated now because what I see on the documentation is not working. I read this part of the documentation: signInWithEmailAndPassword but when I use it in my nodejs code that I deploy to Firebase Cloud functions I get the error:
TypeError: auth.signInWithEmailAndPassword is not a function
Note that auth is actually auth(), I just decided to store the result of auth() in the variable auth, so don't let it confuse you.
I looked at the documentation and I don't see anything wrong I'm doing. This post Firebase Auth On The Server With Node.JS / Express and got this for it
If you initialize the Node.js SDK with an API key instead of a service account, you can use the normal client-side auth methods like authWithEmailAndPassword()
Currently I initialize it like this:
admin.initializeApp(functions.config().firebase)
What exactly am I expected to change so that the signInWithEmailAndPassword method becomes available on the object?
Do I really need to get a API key and initialize it like I'm initializing a frontend project when I'm using firebase-admin on a nodejs server?
Cloud Functions run on a trusted environment, and is using the Firebase Admin SDK to access Firebase services. There is no way (nor usually a need) to sign in as a user with email+password using the Admin SDK.
The Firebase Admin SDK runs with administrative privileges, giving it already has full access to the entire Firebase project that the code runs in.

Firebase cloud function "Your client does not have permission to get URL /200 from this server"

I just made a firebase cloud function :
exports.deleteAfterSevenDays = functions.https.onRequest((req, res) => {...
I deployed the function and got a function URL. When I request this url from my browser I get the following message :
"Error: Forbidden Your client does not have permission to get URL /200
from this server."
I have just updated to firebase Blaze plan because I thought there were limitations with Spark plan, but it still doesn't work.
In my firebase cloud function logs it is written "Function execution took 572 ms, finished with status code: 302".
My cron job "has been disabled automatically because of too many failed executions".
Do you see what's wrong?
Cloud function should have a role with member called "All users" to invoke this function from anywhere/anyone irrespective of an authorization.
Without Authorization:
Go to the cloud function tab
Select your cloud function (check box)
Click "Add members" under Permissions tab in the right side
Enter "allUsers" under "New memebers"
Select Role as "Cloud Functions -> Cloud Functions Invoker"
Save
Test your cloud function by just pasting it in the browser
With Authorization:
It's always a good practice to set authorization on your cloud functions
Note: Cloud functions throwing error with "403 Forbidden - Your client does not have permission to get URL" should be called by authorized users.
Simple test:
Click on Cloud shell(icon) terminal in the top
type - gcloud auth print-identity-token
copy the generated token
forming Authorization key to be passed while calling cloud function
4.1 Authorization: bearer generated_token
Use above Authorization key while calling your cloud function
Note:
Never make a cloud function available to allUsers
From Cloud Function docs:
Caution: New HTTP and HTTP callable functions deployed with any
Firebase CLI lower than version 7.7.0 are private by default and throw
HTTP 403 errors when invoked. Either explicitly make these functions
public, or update your Firebase CLI before you deploy any new
functions.
In my case the CLI version was out of date. If you currently get the 403 error, try this:
Delete your Cloud Functions
Update Firebase CLI npm install -g firebase-tools
Re-deploy your functions
To be clear:
Go to your function (make sure your project is selected):
https://console.cloud.google.com/functions/details/us-central1/ssr
Click Permissions Tab
Click Add Permissions
New Principals: allUsers
Role: Cloud Functions Invoker
Done.
J
Changing the IAM role(Cloud Functions Invoker) for targeted cloud function to allUsers should solve this issue. https://console.cloud.google.com/functions
If you face this in 2020 it might also be due to a different access behaviour:
Note: As of January 15, 2020, HTTP functions require authentication by
default. You can specify whether a function allows unauthenticated
invocation at or after deployment.
https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation
Here are the steps
Go the Google Cloud Console(Not Firebase Console) -> Search For Cloud Functions to see the list of functions
Click the checkbox next to the function to which you want to grant
access.
Click Permissions at the top of the screen. The Permissions panel
opens.
Click Add principal.
In the New principals field, type allUsers.
Select the role Cloud Functions > Cloud Functions Invoker from the
Select a role drop-down menu.
Click Save.
Enable access from Postman project:
Open https://console.cloud.google.com/functions
Open cloud shell (right top terminal icon)
Write: gcloud auth print-identity-token
Copy your token and open your Posman
Right click on your collection -> Edit
Authorization -> Choose type OAuth 2.0
Paste your token in the Access Token
Note: You can do the same for a single request or folder.
This might be far fetched but if you have interrupted a cloud function deployment, then redeployed the function (which lead to an error), and after that you redeployed the function successfully this could have caused the issue.
I am trying to reproduce, but simple deleting the function in the firebase console and redeploying worked for me.
it happens to me after i upgraded all NPM packages and then deployed...
i delete all the functions from the cloude and re-deplyed them. it solve me this error immediately. without change permisions or any other cahnge
I know this doesn't make sense, or not a real solution but I solved it by making my account an Owner of the Firebase project. It was working nice while I was Editor but stopped working suddenly and setting my account as Owner solved it for now.
I guess it has to do with certain account having proper access to the Service Account which is the actual interface with Firebase Functions and Google Cloud API.
In my case, I made error in Postman
when I typed Body of Request, I didn't switched format from Text to JSON.
Check that part.

Resources