how to add custom roles in firebase auth in flutter app? - firebase

I am trying to add Custom roles to my user in my Flutter app. I saw some tutorials which uses Cloud functions to assign roles to user using Node js language(not dart) script because one should not assign customRoles from the frontEnd side of app.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.addAdminRole = function.https.onCall((data,context) => {
return admin.auth.getUserByEmail(data.email).then(user => {
return admin.auth().setCustomUserClaims(user.uid,{
admin: true
})
})
})
But as I am okay with the risks and I can't use this js code so I want to know that is there any way to setCustomRoles in dart(flutter) language ?

The ability to set custom claims for a user is only available in our SDKs for trusted environments, such as the Admin SDK for Node.js that used in the code in your question.
This functionality is not available in the client-side SDK by design, as it'd be a huge security risk to allow this. While you may think this is acceptable, the client-side SDKs will not help you going down this path.
The only way to do this from a Flutter app, is to create a Cloud Function like the one you have, and call that from your Flutter code. This also then gives you a chance to secure the operation in Cloud Functions by checking if the user is authorized to add the claim to their account.

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 should be the security rules while using two different firebase project accessing each other's data?

I'm using two different firebase project in two different flutter android apps. One of the firestore-database is holding some store's data and the other one is holding users Authentication-Database. Let's say, name of the first project is 'store-owners' and name of the second one is 'customer'. I want 'store-owners' data is accessible only and only if the user is registered in 'customer' project. How should be the security rules for the 'store-owners' project? Thanks :)
That's impossible with security rules only. You cannot authenticate users of one project from security rules of others. You would have run your own server or Cloud functions, initialize both the projects in it and then use the Admin SDK access the through it.
// Initialize the default app
admin.initializeApp(defaultAppConfig);
// Initialize another app with a different config
var otherApp = admin.initializeApp(otherAppConfig, 'other');
console.log(admin.app().name); // '[DEFAULT]'
console.log(otherApp.name); // 'other'
// Use the shorthand notation to retrieve the default app's services
const defaultAuth = admin.auth();
const defaultDatabase = admin.database();
// Use the otherApp variable to retrieve the other app's services
const otherAuth = otherApp.auth();
const otherDatabase = otherApp.database();
That way you can write functions which will authenticate users from your auth projects and then read the data from the project where the data is stored.
You can read more about initializing multiple apps in the documenation.
To summarize the flow:
Call function => Authenticate User => Return relevant data
You would have to manually check if the user can access the requested data or not. Firebase Custom Claims may be handy to do that.

Firebase functions authorize only requests from Firebase hosting app

I have a simple Firebase Hosting web application (based on a Vue app) which invokes Firebase Function (Google cloud function):
import firebase from "firebase/app";
import "firebase/functions";
firebase.initializeApp(firebaseConfig);
let functions = firebase.app().functions("us-west4");
let testFunction = functions.httpsCallable("testFunction");
and corresponding functions index.js file:
const functions = require("firebase-functions");
exports.testFunction = functions.region("us-west4").https.onCall(async (data, context) => {
console.log("Very important things here");
return {"response": "data"};
});
From security perspective is it possible to
Allow this invocation only from my domain name (Firebase hosting) myhostedapp.web.app
Check for any kind of authentication (e.g. token) that my JS app provides during the request?
I've tried accessing context.auth property (see docs) buth seems like some kind of service account is required and this cannot be used when called from Firebase hosting web application.
Basically I don't want my function to be publicly accessible (simple invocation via trigger url), so any advice or best practice for securing Firebase Hosting + Functions would be appreciated.
Firebase just released a new feature called App Check that does precisely this: it allows the Cloud Functions in your project to only be invoked from apps that are registered in that project.
For web apps this happens through reCAPTCHA v3, which . Then once you enable enforcement of the check on Cloud Functions, it will reject any requests coming from other sources.
You'll typically want to combine App Check with your current user-based approach, so that you can easily block calls from outside your web app, but also still ensure authenticated users only can make calls that they're authorized for.

How do you read the userInfo of another user with Firebase's cloud functions?

I had in mind to create a cloud function that let a user read some of the user infos of another user under certaine conditions.
For example:
const user1 = ??? // user1 is the current user
const user1Data = await firestore().collection('Users').doc('user1.uid').get()
const user2 = ??? // user2 is the user whith user2.uid == user1Data.partnerUid
const user2Data = await firestore().collection('Users').doc('user2.uid').get()
if (user1Data.partnerEmail == user2.email && user1Data.partnerEmail == user2.email) {
// ...
// the endpoint deliver some of the user2 data to user1.
// ...
}
I have seen the documentation of Cloud functions:
https://firebase.google.com/docs/reference/functions/providers_auth_
I have seen that with the admin API we can call getUser:
admin.auth().getUser(uid)
The difference between functions.auth() and admin.auth() is not clear for me. Can we call admin within cloud functions ?
The difference between functions.auth() and admin.auth() is not clear for me.
When you import functions from firebase-functions, all that gets you is an SDK used for building the definition of functions for deployment. It doesn't do anything else. You can't access user data using functions.
When you import admin from firebase-admin, that gives you access to the Firebase Admin SDK that can actually manage user data in Firebase Authentication. You will want to use this to look up and modify users as needed, and it works just fine when running code in Cloud Functions.
The difference between functions.auth() and admin.auth() is not clear for me. Can we call admin within cloud functions ?
Basically functions.auth(), will let you trigger Cloud Functions in response to the creation and deletion of Firebase user accounts. For example, you could send a welcome email to a user who has just created an account in your app:
exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
// ...
});
functions.auth() is from the cloud function package:
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
Using the above package you can preform firestore, database or auth triggers that will run in response to creating data in the database or creating a new user...
// The Firebase Admin SDK to access Cloud Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
The firebase admin sdk is used to access the database from privileged environments example inside cloud functions.
Check the following links:
https://firebase.google.com/docs/functions/use-cases
https://firebase.google.com/docs/functions/auth-events
https://firebase.google.com/docs/admin/setup
https://firebase.google.com/docs/functions/auth-events

How to notify a Firebase Admin SDK user using a cloud function?

I am a student developing an app and I have some back-end python code that utilizes the Firebase admin SDK. The app with provide an interface to an proprietary algorithm that cannot be moved into the a cloud function and so must stay within the back-end server. When a user makes a request to the algorithm, they will do so by uploading a document to Firestore with information the back-end needs to process their request.
Once a user uploads a document, an onCreate() cloud function is triggered, the goal of this function is to simply notify the back-end that there is a pending request, so that it can process it and send back to the user.
This is where I am struggling, I haven't been able to deduce a way to trigger action on the back-end from within the cloud function. I am hoping to find a way to accomplish this through Firebase without the need to implement additional libraries etc.
A way to generalize my issue would be:
How would you notify an Firebase Admin SDK user through a Cloud Function?
FCM is used for sending messages and notifications to mobile clients. It doesn't work for sending messages to backend components.
If you want to notify some backend component, you typically use an HTTP endpoint or pubsub messaging.
Firebase Functions SDK already uses the Firebase Admin SDK under the hood. So if you set up a Cloud Functions trigger in Node.js, you can access Admin SDK from the Function itself. For instance, taking a Cloud Storage trigger as an example:
const admin = require('firebase-admin');
admin.initializeApp();
exports.fn = functions.storage.object().onFinalize((object) => {
// Call Admin SDK APIs
});
Similar integrations should be possible with Python as well: https://medium.com/#hiranya911/firebase-using-the-python-admin-sdk-on-google-cloud-functions-590f50226286

Resources