I'm building a private note app in Firebase realtime database, Android environment,
and now, I'd like to add authentificaion features with google sign-in in my app.
Until now, I tried several Rules in 'Rules playground', but it's not working well.
DB is like following:
{
"items" : {
"-MwtOrIBmhaoiGtSjzRl" : {
"key" : "-MwtOrIBmhaoiGtSjzRl",
"modifiedAt" : "2022-02-27 04:19:15.782677",
"string" : "test11"
},
"-MwvRBvCJ3hVJS3Qx1M3" : {
"key" : "-MwvRBvCJ3hVJS3Qx1M3",
"modifiedAt" : "2022-02-27 13:48:43.081140",
"string" : "Test2"
}
}
}
And the rules are like following:
{
"rules":{
"items": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid",
},
".indexOn": "modifiedAt"
}
}
}
In Rules playground, I tried 'get' simulation and the result is
'Simulated read denied'
{
"auth": {
"uid": "e41ac05f-6c93-40c8-add6-90bccf8ab80d",
"token": {
"sub": "e41ac05f-6c93-40c8-add6-90bccf8ab80d",
"firebase": {
"sign_in_provider": "google.com"
},
"email": "",
"email_verified": false,
"phone_number": "",
"name": ""
}
},
"resource": {
"key": "value"
},
"path": "/item",
"method": "get",
"time": "2022-02-27T14:44:13.766Z",
"isAdmin": false
}
Can I get some help?
One strange thing is that the follwing rules are not working well also.
{
"rules":{
"items": {
"$uid": {
".read": true,
".write": true,
},
".indexOn": "modifiedAt"
}
}
}
The key values you have under items are not Firebase Auth UIDs. They are push IDs randomly generated from your client app code. A push ID has nothing to do with the identity of the person who added that data.
To be clear, this value: "MwtOrIBmhaoiGtSjzRl" is not a UID. And it doesn't match the UID you're specifying here: "e41ac05f-6c93-40c8-add6-90bccf8ab80d".
If you want to use the user's UID as the key of the data to add to the database, don't use push(). You should instead build a path to the data using the user's UID in your code using setValue() as shown in the documentation.
Related
How to set security rules for Firebase realtime database structure as below:
users: {
...
...
...
},
books: {
...
...
...
},
sales: {
...
...
...
}
Condition: Firebase auth is set to email/password and only user logged-in with emails ending with domain [mydomain.co.in] must be able to read or write to parent node. Without using custom claims.
Adding below security rules is applied/working only for the the first parent node [users] and not to all, what is a miss here?
{
"rules": {
".read": false,
".write": false,
"users": {
".read": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".write": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".indexOn": "name"
},
"books": {
".read": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".write": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".indexOn": "title"
},
"sales": {
".read": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".write": "auth.token.email.matches(/.*#mydomain.co.in$/)",
".indexOn": "price"
},
}
}
Try below enclosed within uid field?
Reference https://firebase.google.com/docs/reference/security/database
same code works with auth.token.email.matches(/.*#mydomain.co.in$/)
{
"rules":{
".read": "false",
".write": "false",
"users":{
"$uid":{
".read":" auth.token.email.endsWith('#mydomain.co.in')",
".write":" auth.token.email.endsWith('#mydomain.co.in')",
".indexOn":"name"
}
},
"books":{
"$uid":{
".read":" auth.token.email.endsWith('#mydomain.co.in')",
".write":" auth.token.email.endsWith('#mydomain.co.in')",
".indexOn":"title"
}
},
"sales":{
"$uid":{
".read":" auth.token.email.endsWith('#mydomain.co.in')",
".write":" auth.token.email.endsWith('#mydomain.co.in')",
".indexOn":"price"
}
}
}
}
Auth Token payload
{
"token":{
"email": "test#mydomain.co.in"
}
}
I would like to add firebase database rule to allow anyone to increment the "count" inside the message object. Is it possible to do so? If so, how should I write the rule for updating the count? Thanks!
{
"messages": {
"message0": {
"content": "Hello",
"count": 5
},
"message1": {
"content": "Goodbye",
"count": 10
},
...
}
}
I tried below rule, but it doesn't seem to work:
{
"rules": {
"messages": {
"$message": {
"count": {
".read": true,
".write": true,
}
}
}
}
}
I'm creating a Google docs type of app where multiple users can edit a document in real-time.
These are my security rules:
{
"rules": {
"docs": {
"$doc_id": {
".read": "auth.token.doc_id === $doc_id",
".write": "auth.token.doc_id === $doc_id"
}
}
}
}
This is my Auth token payload (example)
{
"provider": "anonymous",
"uid": "e71afdf1-2b31-4c75-8f10-a9b0f916915e",
"token": {
"doc_id": 11
}
}
So when I try to read this path /docs/11/data I get a Simulated read denied error.
On the other hand when I put this rule instead
".read": "auth.token.doc_id === 11", (i.e. hard code $doc_id as 11)
The read passes.
But isn't $doc_id equal to 11 when I read /docs/11/data or am I misunderstanding something?
P.S. In case it matters, here is the data inside my database
{
"docs": {
"2": {
"data": {
"title": "test"
}
},
"11": {
"data": {
"title": "test"
}
}
}
}
TLDR: How can I set up the DB access rules so that I can read all the items I have authorization to from a given endpoint?
I have a similar set of data in my Firebase database:
"employees" : [ {
"first_name" : "Constance",
"last_name" : "Smith",
"createdBy: "vdBoGzI2i9f12er6ZcPjG9AiTip2"
}, {
"first_name" : "Agatha",
"last_name" : "Carlton",
"createdBy: "Tpg1mFR99meDV2QGT44pU6y7s1T2"
},
...
}
I also have a list of application users:
"users" : {
"Tpg1mFR99meDV2QGT44pU6y7s1T2" : {
"name" : "Alex Lund",
"isAdmin": true
},
"vdBoGzI2i9f12er6ZcPjG9AiTip2" : {
"name" : "David Peterson",
"isAdmin": false
},
...
},
Basic users will have access just to the employees they created; the admin will be able to read everything.
{
"rules": {
".write": "auth != null",
"employees": {
"$employee": {
".read": "root.child('users').child(auth.uid).child('isAdmin').val() === true || data.child('createdBy').val() === auth.uid"
}
},
}
With this rules, an admin will be able to read ref.child('/employees/0'), but won't have access to ref.child('employees').
How can I get all the employees I have read access to? Is running a query the only solution?
With the rules as you have them now, a query on /users won't work. Since you don't have read permission on /employees any listener on that location will immediately be rejected.
You probably want the rules to be like this:
{
"rules": {
".write": "auth != null",
"employees": {
".read": "root.child('users').child(auth.uid).child('isAdmin').val() === true"
"$employee": {
".read": "data.child('createdBy').val() === auth.uid"
}
},
}
With these rules administrators can read (and thus query) /users, while regular users can only access children that they created.
This is a common pitfall when it comes to Firebase Database security rules and is typically referred to as "rules are not filters". See the relevant section in the documentation, this original Q&A on it and any of the questions in this list.
I am trying to prevent unwanted fields to be added to my user objects.
--> A user can have a phone and a username (but doesn't have to --> newData.hasChildren(['phone', 'username']) doesn't work here).
I first tried this:
"users": {
"$uid": {
"$other": {
".validate": "['phone', 'username'].indexOf($other) > -1"
}
}
}
I get an error because of the array :(
So then I thought about doing something like this but it's really not great if I have many potential fields
"$other": {
".validate": "$other === 'phone' || $other === 'username'"
}
Finally, I created a node in my Firebase called 'rules' and did this:
"rules": {
"users": {
"fields": {
"phone": true,
"username": true
}
}
}
And then my new validation rule in my user object is:
"$other": {
".validate": "root.child('rules/users/fields/'+$other).val() === true"
}
My question is: Is this a correct way to restrict field names ?
Thank you very much for your answer :) I am pretty new to Firebase but I am having a lot of fun trying it out!
To restrict an object in your Firebase to only have the specified keys, try using one additional wildcard child that will match any attributes not already specified, and reject the write if it contains one of these unmatched attributes:
"rules": {
"users": {
"$userid": {
".validate": "newData.hasChildren(['phone', 'username'])",
"phone": {
".validate": "newData.isNumber()"
},
"username": {
".validate": "newData.isString()"
},
"$other": {
".validate": false
}
}
}
}