Allow only admins to write data - Firebase Realtime Database - Security Rules - firebase

I want to give .write permission only to those authenticated users with isAdmin:true
Below is the structure of Database.
In the clients(users) node uid is the Firebase generated auth uid.
{
"clients" : {
"-M8bGQaB....." : {
"isAdmin" : true,
"uid" : 5gvR1GzT...
}
},
"products" : {
"-M81GzT....." : {
"productName": "Product 1"
},
"-M81GzT....." : {
"productName": "Product 2"
}
}

With your current data structure there is no way to look up the user profile in the security rules, as security rules can't search across all users.
That's why the proper data structure to store user uses their UID as the key. In your case that'd look like:
"clients" : {
"5gvR1GzT..." : {
"isAdmin" : true
}
},
With this JSON, you can then only allow users to write a product when the isAdmin property for their UID is set to true with:
{
"rules": {
"products": {
"$productid": {
".write": "root.child('clients').child(auth.uid).child('isAdmin').val() == true"
}
}
}
}

Related

How to fetch all resources from Firebase database with nested security rules?

In firebase, is it possible to configure a rule so that when a parent resource is fetched, it only returns child items that the user as access to?
I have a data structure like so:
{
application_access_request: {
app_id_1: {
access_key_1: {
email: "abc#b.com"
},
},
app_id_2: {
access_key_2: {
email: xyz#c.com
},
}
}
}
And then I have rules like so:
{
"application_access_request": {
"$appId": {
"$accessId": {
".read": "data.child($accessId).child('email').val() === auth.token.email",
},
}
},
}
As a user logged in with email abc#b.com,
When I request all resources from application_access_request/,
Then I want app_id_1 and it's children to be accessable / returned to the user,
Is it possible to allow reading of all application_access_request but only return apps that the auth'd user has access to?
No, security rules cannot be used to selectively return information (see rules are not filters). You may, however, be able to use querying to solve this use case. For example, if your data was structured:
{
application_access_request: {
app1: {
access_key: "user#example.com"
},
app2: {
access_key: "user2#example.com"
}
}
}
You can use query-based rules to limit querying:
"application_access_request": {
".read": "auth.uid != null && auth.token.email_verified &&
query.orderByChild == 'access_key' &&
query.equalTo == auth.token.email"
}

How to set Firebase Realtime database rules to read only child node?

I have a node called profiles that have a list of id's.
I want to allow read access to the child nodes only and prevent reading all profiles.
This is what I have in rules, but it allow to read all profiles.
{
"rules": {
"profiles":{
".read": true,
".write": false
}
}
}
and this is what I have under profiles
{
"1" : {
"id" : "1",
"name" : "test1"
},
"2" : {
"id" : "1",
"name" : "test2"
}
}
Typically you'll store each user's profile under a key that has the value of their Firebase Authentication UID. So:
{
"profiles": {
"uidOfUser1": {
"id" : "1",
"name" : "test1"
}
"uidOfUser2": {
"id" : "2",
"name" : "test2"
}
}
}
In that case you can secure it with these rules:
{
"rules": {
"profiles": {
"$user_id": {
// grants read access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".read": "$user_id === auth.uid"
}
}
}
}
In the security rules the value of auth.uid is the UID of the user that is currently signed in to Firebase Authentication. There is no way to spoof this value, so it's a great way to secure data access. The above rules allow a user to read a specific profile when their auth.uid matches the key of the profile. So uidOfUser1 or uidOfUser2.
Also check out the Firebase documentation on securing user data, which describes it in more detail.

Allow un-authenticated users to Write but not read any other child

So I 've a application where users are able to write in my database(ONLY during SIGNUP). I want to grant them read/write access to JUST their child node and not my whole database. Currently, an un-authenticated user has full write access to my whole database node. This is my Firebase user node-
"users" : {
"-LAQxFS_GNA-xKewLYgDe" : {
"name" : "XYZ"
"phone" : "988900000"
},
"-LAffLlvl9ZTm-D1FMS8" : {
"name" : "XXYYZZ"
"phone" : "32223333"
},
....and so on
Here, i want this child user "LAQxFS_GNA-xKewLYgDe" to only access his node without any access to other child nodes.
Here's my rules
{
"rules": {
"messages":{
".read":true,
".write":true
}
, "books":{
".read":true,
".write":true
},
"aTime":{
".read":true,
".write":true
},
"users":{
".read":false,
".write":true
}
}
}
PS: I've my own custom signup page where users enter their name and phone number. This info is saved in "users" node.

Firebase Realtime Database read rule for specific user

How can I add new rule to Firebase Realtime Database so that users can read data where recid equal to user ID?
I have a massage table with this structure:
"messages" : {
"-KyyjeMOtc7fWAsOiuiP" : {
"recid" : "FL5hyQJrsHWRQsRtiLe1PxkyRnk1",
"senderid" : "6K6pQHaCishDlCb0Y9AaN3zI22n1",
"text" : "hi"
},
"-KyykczCNpsSL6a1t8vt" : {
"recid" : "FL5hyQJrsHWRQsRtiLe1PxkyRnk1",
"senderid" : "6K6pQHaCishDlCb0Y9AaN3zI22n1",
"text" : "test"
},
}
I want a rule that when data is added to the database, only the user whose uid is equal to recid can see the data.
To achieve this, you can create user-based security rules for your database, something similar to:
{
"rules": {
"messages": {
"$messageId": {
".read": "auth.uid == data.child('recid').val()",
".write": "auth !== null"
}
}
}
}
In this example, $messageId uses a $location variable that will match any key under your messages list. Then, we grant read access only if the current user's auth.uid matches the recid child value.

How to make a 'super admin' in Firebase?

A super admin is an user with special uid which is able to access of everyone to edit their profile and publish new content.
How to make a super admin?
Consider using custom user attributes. It is more efficient and cheaper than using Real Time Database to lookup if a user is an Admin on every authenticated request:
https://firebase.google.com/docs/auth/admin/custom-claims
You would set the Admin role on the user upon creation:
admin.auth().setCustomUserClaims(uid, {admin: true})
You can propagate it to the client after ID token refresh.
currentUser.getIdToken(true)
Then you can simply enforce the rule:
{
"rules": {
"adminContent": {
".read": "auth.token.admin === true",
".write": "auth.token.admin === true",
}
}
}
If you don't use rules or Firebase RTDB, then enforce it on your backend by parsing it from the ID token via Firebase Admin SDK:
// Verify the ID token first.
admin.auth().verifyIdToken(idToken).then((claims) => {
if (claims.admin === true) {
// Allow access to requested admin resource.
}
});
Basically, it's all about data structure and the belonging security rules.
To get started, build a data structure where you have some kind of user roles in it.
For example like this:
{
"data" : {
"user1id" : {
"name" : "MisterX"
},
"user2id" : {
"name" : "John Doe"
}
},
"users" : {
"user1id" : {
"role" : "admin"
},
"user2id" : {
"role" : "member"
}
}
}
Each user has a property called role.
Now you can define your security rules and make use of the role property to define the right access rights:
"data" : {
"$userid" : {
".read" : true,
".write" : "root.child('users').child(auth.uid).child('role') === 'admin'",
}
}
In the case above just admins are able to write to the data/userid node. You can apply this to all the different nodes you want to.

Resources