I want to make different permission for different user roles.
For example, when the user is not super-owner, don't let him write in my items table.
This is what I tried to do:
{
"rules": {
"items": {
".write": "auth.authority == 'super-owner'"
}
}
}
But I notice that the authority field is stored in my users node I created on my own and is releated to the Firebase auth. How I can access users->authority of current logged in user through the rules?
Update: I did try this:
".read": "root.child('users/'+auth.uid).authority.exists()",
but I get Error saving rules - Line 10: No such method/property 'authority'.
You get this error because root.child('users/'+auth.uid) returns instance of DataSnapshot which does not have authority property of course. But it has hasChild method.
For full list of methods about DataSnapshot visit the following link.
https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot.
Try this.
".read": "root.child('users/'+auth.uid).hasChild('authority')",
".write": "root.child('users/'+auth.uid).hasChild('authority') && root.child('users/'+auth.uid+'/authority').val() == 'super-owner'"
or this
".read": "root.child('users/'+auth.uid+'/authority').exists()",
".write": "root.child('users/'+auth.uid+'/authority').exists() && root.child('users/'+auth.uid+'/authority').val() == 'super-owner'"
or the shortest version
".read": "root.child('users/'+auth.uid+'/authority').val() !== null",
".write": "root.child('users/'+auth.uid+'/authority').val() == 'super-owner'"
Related
I am trying to block hackers from modifying or seeing the data on my Firebase database. Users in my database contains the user IDs of all the users in Authentication tab. Can I make the database to only let see data by the user logged in?
This is my database structure:
firebase database structure
I want to allow users to modify their own user ID's entry in "users" and I want to allow only the admin to control "orders". Im using Firebase in a Electron app so client is connecting to firebase in Node.js
Yes, this is definitely doable using Firebase Database Rules
What you've described seems like it would have three parts, but they we they combine also affects how you need to write them.
I'll start by going over the 3 pieces separately and then will move into combining them.
Read/Write By Only Logged In Users
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
By placing this at the top level of your rules, you will prevent any reading or writing by anyone not logged in through one of the supported Firebase authentication methods.
Users Modifying User Entry
{
"rules": {
"users": {
"$uid": {
".write": "auth.uid === $uid"
}
}
}
}
This specifies that under the user path, for each user id (using the $uid syntax to specify it as a variable to be used later), only allow writing when the current authenticated user id matches that same id.
Admin Control Of Orders
{
"rules": {
"orders": {
".read": "auth != null && auth.token.isAdmin",
".write": "auth != null && auth.token.isAdmin"
}
}
}
We take a similar approach for orders as we did for users entries, but instead of checking the user id we simply say that only an admin can do reads and writes anywhere under orders.
Putting It All Together
Now, if these rules came together in a way such that more specific rules overrode less specific rules (like CSS selectors, for instance), then we could simply merge all of the above together like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"orders": {
".read": "auth != null && auth.token.isAdmin",
".write": "auth != null && auth.token.isAdmin"
},
"users": {
"$uid": {
".write": "auth.uid === $uid"
}
}
}
}
However, Firebase database rules are somewhat of an inverse of this. Providing access in shallower rules will override any deeper rules attempting to deny access (although it is possible to grant more privileges in deeper rules). So the above will actually give full read/write access to the entire DB by any logged in user.
In light of that, we will need to be more careful when combining these, to ensure that our separate intents stay valid. Most importantly, the first section Read/Write By Only Logged In Users will be the section that requires modification, since it was at the top level.
Luckily, our rules from parts 2 & 3 take care of most of what we were getting from part 1 anyways. This only holds true if there are only orders and users in your db. The only thing we are missing is a read rule on users. It's not entirely clear what sort of rules you want for reading user data, since you only specify that a user can only write his or her own data, so I will assume that all logged in users can read user data.
The merge then becomes:
{
"rules": {
"orders": {
".read": "auth != null && auth.token.isAdmin",
".write": "auth != null && auth.token.isAdmin"
},
"users": {
".read": "auth != null",
"$uid": {
".write": "auth.uid === $uid"
}
}
}
}
Please note that you will need to duplicate the auth != null rule for read and/or write in other nodes of your db if you have them, since here you only show off orders and users.
Hope that helps!
I am working on the app that I need to connect to the dev firebase.
This firebase has database rules as follows:
"rules": {
// no read access at root level
".read": "auth.uid === 'emailaddressgmailcom'",
".write": false,
What I cannot understand is how auth.uid is specified to be an exact email address?
As far as I tried I only get unique uid provided by Google. (set of numbers and letters)
Hence I can never pass the auth to read from the database, unless I specify my exact uid given by Google in the databse rules, which is not an option because there will be another user who needs an access to db and I do not know his uid.
auth is one of the predefined variables.
By doing auth.uid, you get the user id ("guaranteed to be unique across all providers").
You need, in your Security Rules to use it to defined the access rights of a given user to one or more given resources, as explained here in the doc.
You could compare it to a fixed value, if a certain resource shall be read by a unique user:
".read": "auth.uid === 'HGH656675FHGFGHF3454'"
but usually you compare it to some parts of the path of the node/resource you want to protect, like for example:
{
"rules": {
"users": {
"$user_id": {
// grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
}
}
This is how you should do to solve your problem "there will be another user who needs an access to db and I do not know his uid".
I would suggest you read the entire section about RTDB Security Rules form more details: https://firebase.google.com/docs/database/security
Please try below rules
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
// These rules grant access to a node matching the authenticated
// user's ID from the Firebase auth token
I am using firebase database in my app. I have set the rules to allow normal users to create new childs in the node but I found that it's refused.
this is the writing rules of the node :
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\" || ((newData.exists() && !data.exists()) || auth.token.email == data.child(\"userEmail\").val())",
I think that newData.exists() && !data.exists() should allow users to write in the database but this doesn't happened
this is the rules of the users node :
"users":{
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\" || ((newData.exists() && data.child(\"userEmail\").val() != null) || auth.token.email == data.child(\"userEmail\").val())",
".read": "auth != null"
}
The database strucutre is like that :
-users
-user1
-userName, userEmail ....
-user2
-userName, userEmail .....
when a new user sign up in the app he should be allowed to push his data in the database
this is the database structre :
Ok, I think you're creating extra validation steps that aren't needed.
First
With ".read": "auth != null" on your users root, each user is able to access other user's data, so we should address the access for each user individually.
Second
If you just want to allow users that are authenticated to write and read its own contents, you can remove these extra ((newData.exists() && !data.exists()) and auth.token.email == data.child(\"userEmail\").val()) steps.
Tip: this ((newData.exists() && !data.exists()) comparison means exactly: Write here if you're sending anything but there should be nothing written in this requested "path". You should reflect on the need of this, as I don't know your exact use cases.
Also, I would guess the hardcoded UID you're requesting is of an Admin you've created - I wouldn't recommend this, please read more about user roles on this answer.
To clarify, I think your rules structure should be something like this:
{
"rules": {
".write":"auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\",
".read": "auth.uid == \"DFhNb28506Y345CpJ3Ye7DQNn713\",
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
I want to stop the signup process if the username exists. I don't want to create Email\Password (Authentication) and other info if the username exists
database rules:
{
"rules": {
"users": {
".read": "(auth != null)",
".indexOn": ["username"],
"$uid": {
"$username":{
".write": "(auth != null) && !data.exists() || newData.exists()"
}
}
}
}
}
I have added !data.exists() in .write , but still it duplicate usernames.
And then I added ".validate" to make username atleast 3 characters, to see if the signup process gonna fail if its longer, but it created email\password and other stuff but didn't wrote any data in database root\users\
After registered new user with email\password I got this error, Which means username couldn't be more than 3 characters. How to stop the signup process and show alert message at this situation?
[Firebase/Database][I-RDB03812] setValue: or removeValue: at /users/jt94ARqOoodtU3kYp3W1MtlUZ4m1 failed: permission_denied
Please help me if you could fix the problem.
Your simplified rules are:
{
"rules": {
".write": "(auth != null)",
"users": {
"$uid": {
"username": {
".write": "auth != null && (!data.exists() || !newData.exists())",
So you first grant any authenticated user write access on the root of the data and subsequently say that a user can only write if there is not data a the current location.
That won't work: once you grant permissions at a certain level, you cannot take that permission away on a lower level.
The Firebase documentation describes this as Read and Write rules cascade:
Child rules can only grant additional privileges to what parent nodes have already declared. They cannot revoke a read or write privilege.
Before in my app I was creating accounts successfully until I put some rules
{
"rules": {
"users": {
"$uid": {
// grants write access to the owner of this user
// account whose uid must exactly match the key ($uid)
".write": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in
// with an email and password
".read": "auth !== null && auth.provider === 'password'"
}
}
}
}
then, the accounts are created because I see those accounts in the dashboard. But once I try to create, I am getting this kind of errors
FIREBASE WARNING: set at /users/simplelogin:32 failed: permission_denied
Since you want the user to be able to create their own node initially, you'll need to explicitly allow the case where the location is new.
Based on the documentation on the auth parameter:
".write": "!data.exists() || auth.uid === $uid""
Note: I'm not entirely sure this will work, but felt it'd be more readable as in answer-format than as a "try this" comment.