How should be the security rules while using two different firebase project accessing each other's data? - firebase

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.

Related

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

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.

Why we pass apikey,databaseurl,storageBucket,Domain, appId, messagingSenderId in Firebase Nodejs Project

When initializing Firebase in Nodejs project, why we include apikey,databaseurl,storageBucket,authDomain, appId, messagingSenderId, projectId in Firebase.initializeApp()? Without some of these properties, it is still working, then why do we need to pass it?
And also for security, we use Firebase Authentication for checking user auth.uid, so why do we need to pass the above properties in initializeApp()?
Does passing these properties, Firebase will check it by default? If Firebase checks it by default, we don't need Firebase Authentication then?
I'm a beginner kindly help.
Firebase consists of >18 products these days, and many of them take different configuration data at startup. But since you only call initializeApp once for all these products, you have to pass the configuration data for all products in this one call.
That's why all example in the Firebase documentation and console show how to pass all possible configuration data. Depending on the products you actually use, and the platform you run on, you may need fewer of these values, but including all of them never causes problems.
When you register an app with a Firebase project, the Firebase console provides a Firebase configuration file (Apple/Android apps) or a configuration object (web apps) that you add directly to your local app directory.
That is, a Firebase config file / object associates an app with a specific Firebase project and its resources. It consists of unique and non-secret identifiers for your project. A Firebase config file generally consists of apiKey, databaseURL, projectId, storageBucket, messagingSenderId, appId, measurementId.
These parameters are required by Firebase and Google services to communicate with Firebase server APIs and to associate client data with the Firebase project and Firebase app. The apiKey and the projectId are the mandatory fields in the configuration file/object. And, other fields are optional. Each of the other fields corresponds to an optional part of Firebase.
This is because Firebase contains many services/products such as realtime nosql database services, blob storage, push notifications/messaging, and ofcourse Authentication among many more things.
If you do not desire to use the other parts of Firebase, simply do not reference them nor enable them. It is completely fine to only use Firebase Authentication.
The content of the Firebase config file or object is considered public, including the app's platform-specific ID (Apple bundle ID or Android package name) and the Firebase project-specific values, like the API Key, project ID, Realtime Database URL, and Cloud Storage bucket name. Given this, it is recommended to use Firebase Security Rules to protect your data and files in Realtime Database, Cloud Firestore, and Cloud Storage.

Developing an SDK - How to send Firebase events to SDK firebase account, not the app one?

Firebase is great, it helps in so many ways, and well-integrated with crashalytics, Google Analytics, Google Tag Manager, you name it.
We are building a mobile SDK, however, it seems that you can only link to Firebase on the app level (you can't initialise your own SDK to send to a different account than App's Firebase account).
Is there a workaround to allow me as an SDK developer to collect events, crash reports,.... to a Firebase account related to the SDK alone, regardless to the app that is using the SDK?
Many thanks
You can initialize more than one instance of the SDK at once. However, you should make consumers of your SDK aware that it is doing so and they should have a clear way to opt-out.
When an application is launched, the FirebaseInitProvider will handle initialization of the default application instance. This default app instance has a name of "[DEFAULT]".
If you wanted to have a second user logged in, make use of a separate project, make use of a secondary database, and so on - you can just initialize another application instance. Importantly (taken from the docs), any FirebaseApp initialization must occur only in the main process of the app. Use of Firebase in processes other than the main process is not supported and will likely cause problems related to resource contention.
This is done using FirebaseApp.initializeApp() like so:
FirebaseApp nameApp = FirebaseApp.initializeApp(context, config, "name");
To replicate the default instance so you can have more than one user logged in, you can use:
FirebaseApp defaultApp = FirebaseApp.getInstance();
FirebaseApp secondaryApp = FirebaseApp.initializeApp(
defaultApp.getApplicationContext(),
defaultApp.getOptions(),
"secondary"
);
To use a separate instance entirely, you load your configuration into a FirebaseOptions object using:
FirebaseOptions sdkAppOptions = new FirebaseOptions.Builder()
.setApiKey(sdkApiKey)
.setApplicationId(sdkAppId)
.setDatabaseUrl(sdkDatabaseUrl)
.setGcmSenderId(sdkGcmSenderId)
.setProjectId(sdkProjectId)
.setStorageBucket(sdkStorageBucket)
.build();
FirebaseApp sdkApp = FirebaseApp.initializeApp(
sdkContext,
sdkAppOptions,
"com-example-mysdkproject" // <- use namespace as best practice
);
Once you have an instance of FirebaseApp, you can then pass it through to other the other services using:
FirebaseAuth sdkAuth = FirebaseAuth.getInstance(sdkApp);
// or
FirebaseApp sdkApp = FirebaseApp.getInstance("com-example-mysdkproject");
FirebaseAuth sdkAuth = FirebaseAuth.getInstance();

Firebase admin sdk unauthenticated query to secondary firestore DB

Scenario: I have a firestore document(document 1) in Database(DATABASE 1) that is publicly readable i.e I can make a REST GET call unauthenticated and get the data.
I have another firestore Database(DATABASE 2), in which i want to clone
data of document 1 and save it to DATABASE 2 document.
Question: How can i retrieve the DATABASE 1 document 1 data from DATABASE 2 Admin SDK ?
Motivation: REST response requires parsing, i am hoping to make Firebase lib SDK call that doesnt requires any parsing.
FEW NOTES:
I don't want to expose DATABASE 2 Service Account Creds to DATABASE 1 Admin.
Wondering if its possible to create secondary instance of firebase Admin using DATABASE 1 project-id and/or url without exposing and creds.
This is definitely possible, but you are going to need to expose credentials for a service account in the second project in order to use the admin sdk for that. If this is possible in your case, all you have to do is instantiate the project with a firebaseOptions referencing to a different project, as you can see in this documentation:
const secondaryServiceAccount = require('./path/to/serviceAccountKey.json');
const secondaryAppConfig = {
credential: admin.credential.cert(secondaryServiceAccount),
projectId: "YOUR_SECOND_PROJECT_ID"
};
const secondary = admin.initializeApp(secondaryAppConfig, 'secondary');
and access whatever services you need by using the secondary variable, eg. to access the second Firestore project use secondary.firestore().
As mentioned by Frank in the comments an alternative to this is to use the regular Firestore SDK, you can find more information in this documentation, the process is quite similar.

How to make firebase database rule work with admin.database().ref (cloud function)

I'm working with Cloud Function for Firebase. When I use admin.database().ref then all the rules that applied to the database were ignored. With admin, I can do anything. To be clear:
I have a real-time database with have a set of rules such as; name must be string and length >= 50,...
It works when using the SDK, all the invalid data will be denied. But when I move to use firebase cloud function (to reduce work in client side by providing a set of https endpoints) it didn't work anymore.
So, I wonder if there is any way to make it work? I was thinking about:
find something replace for admin.database() (took a look on
event.data.ref already but this does not work in my case - HTTP request)
verify data in cloud function (not nice)
Could you give me some hints/clues?
This is the expected default behavior of the Firebase Admin SDKs: the code accesses the database with administrative privileges.
If you want to limit what the code can do, you can initialize it to run as a specific UID. From the documentation on Authenticate with limited privileges:
To get more fine-grained control over the resources a Firebase app instance can access, use a unique identifier in your Security Rules to represent your service.
...
Then, on your server, when you initialize the Firebase app, use the databaseAuthVariableOverride option to override the auth object used by your database rules. In this custom auth object, set the uid field to the identifier you used to represent your service in your Security Rules.
// Initialize the app with a custom auth variable, limiting the server's access
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://databaseName.firebaseio.com",
databaseAuthVariableOverride: {
uid: "my-service-worker"
}
});
Please see the linked documentation for the complete example.

Resources