I want to allow specific persons to edit the data on the Firebase Database that users are not allowed to edit.
I am allowing by simply allowing them to write with their user ids:
".write": "auth != null && auth.uid === 'h7yic7LeS123asdfsdgwPrfKZ2'"
Is this a safe method? Do I have to use token based authentication to assign roles to the moderators?
If you use a standard way to authenticate your user (i.e. login) like, e.g. Firebase UI (https://github.com/firebase/firebaseui-web), this is indeed a safe method.
As a matter of fact, using such an authentication mechanism will populate auth.uid with the uid of the user and therefore only user with uid h7yic7LeS123asdfsdgwPrfKZ2 will be able to write to the corresponding database node.
Since you are mentioning "specific personS" (i.e. more than one user) you may use a different approach than hardcoding the users' uid in the security rule. You could, for example, use a rule like this one:
".write": "auth != null && root.child('admins/' + auth.uid).exists()"
In this case you would declare the uids of the authorised persons as children of the "admins" database node:
-admins
-h7yic7LeS123asdfsdgwPrfKZ2: true
Related
If i write write: "auth != null" who can write ?
Only the person which has my google account and password or all persons who have a google account?
I want to be the only one who can write to the database page but I can't change the rule to false.
If I write: ".write": "auth != null" who can write to my database?
As Frank said, only people who have authenticated using Firebase can write with this rule. If you have no way for users to sign up for your app, then you'd be the only one who can write. If you have users create an account, they're "authenticated" as well and can write. If you want to limit writing just to your user account, get your user id and use this rule where MY_USER_ID is your uid, or look into custom claims.
".write": "'MY_USER_ID' === auth.uid"
This assumes you want to write from some interface other than directly in Firebase. If you want to prevent all writing and manually upload/edit copy directly into Firebase, you can set:
".write": false
...which would prevent all writes from users anywhere, but which would still allow you to edit your data in the console.
If you have this rule:
".write": "auth != null"
Any user who is authenticated can write to your database. That means anyone who signs in with a method that you've enabled in your Firebase Authentication console .
After reading lots of tutorials and StackOverflow's questions I still couldn't figure how to do it.
All the tutorials start with the following rule:
"users":{
"$uid":{
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
But how to allow a new user in the users node when a new user log in (auth != null) and keep the read and write user-specific path privileges ?
In other words:
Is there a way to make a new user be inserted in the users node after login, and at the same time restrain him to only read and write to his own node ?
Another question. I have a write rule in another node with newData.exists(). In the Simulator when I try to write null data to the node it denies it as expected, but it allows me to write null to a child of this same node. Shouldn't the node write rule cascade to its children ?
The rules you have above will match $uid to auth.uid. So, for example if a user's UID is cKzMyjImSBX6ybzeCCCjf0qbTym1, they will be only be able to read & write at /users/cKzMyjImSBX6ybzeCCCjf0qbTym1 in your database, regardless of whether or not this key currently exists (if it doesn't exist when written to, it will be created).
From the Firebase documentation on rules:
Once a user authenticates, the auth variable in your Firebase Database
Rules rules will be populated with the user's information. This
information includes their unique identifier (uid) as well as linked
account data, such as a Facebook id or an email address, and other
info.
I'm using Firebase for my app and was wondering how to block certain users. I see on the Auth tab of the console, there are "delete" and "disable" options. What do those do? I haven't been able to find documentation on that. Will one of those allow me to block a user?
What I mean by blocking a user is for the ".read": "auth != null" rule to prevent him from accessing data on the database
The disable feature consist in preventing that user to authenticate. So if he tries to authenticate he will fail with error code INVALID_CREDENTIALS and he won't have access to the data that has the ".read": "auth != null" rule. It works like he is deleted but the admin still have the power to reactivate the user account.
If you want to build a list of "blocked users" that will be able to authenticate but will have restricted access, you can store the blocked ids in a node on your firebase database like /databaseRoot/blockedUsers and then work with the security and rules.
".read": "auth != null && !root.child('blockedUsers').hasChild(auth.uid)"
blockedUsers could look like the tree bellow but you could also add some other info under the userId such as the date this user was blocked.
/databaseRoot
/blockedUsers
userId1 : true
userId2 : true
Adding the user to this list will depend on your necessity. You can do it manually by accessing the firebase console and adding the user id to the node. Or, if you want to block an user based on an event on the application, you could simply call something like
ref.child('blockedUsers').child(userIdToBlock).set(true);
For each security rule, is it necessary to always check auth !== null? It seems redundant to have to do this for every child rule.
I checked Firebase's own Firechat security rules and the enforcement is not consistent at all. There are rules that use auth.uid but do not check for null auth.
What happens if auth is null and auth.uid is used in the rule?
And what is the recommended practice regarding checking auth !== null?
You need to check auth !== null if you want the data restricted to any authenticated user.
You need to check for auth.uid == $uid when you want the data restricted to the currently authenticated user. You don't need to check for auth == null && auth.uid != $uid because auth.uid == $uid will evaluate to false if the auth variable is null. But you can still include both to be thorough.
So essentially, auth != null is restricts the data to any authenticated user, and auth.uid != null restricts to the single currently authenticated user.
Now for some extra curricular information.
Use the Bolt compiler to simplify common rules.
Security Rules are flexible, but they don't have much convenience for reproducing common rules. For that, you can use the Bolt compiler.
The Bolt compiler allows you to create types and assign them to paths in your Firebase database. These types act as schema. You can also create functions that abstract common rules.
I wrote a blog post on securing user data with Bolt. It goes through what you need to know to keep user data secured with types and functions in Bolt.
isCurrentUser(uid) = auth != null && auth.uid == uid;
isAuthenticated() = auth != null
path /users/$uid {
read() = isAuthenticated() // any authenticated user can read
write() = isCurrentUser($uid);
}
In the example above we reuse the isCurrentUser() function three separate times. This will make changes moving forward much easier to deal with.
In my application I have a number of different user groups, such as chat rooms and specific projects.
How can I allow the users in those groups to share their presence data, and see the presence of every other user in the group, but keep that data private from the outside world?
First, you'll need to begin authenticating your users by using one of the supported Firebase authentication mechanisms. More information about authentication in Firebase is available at https://www.firebase.com/docs/security/authentication.html.
Once you have begun authenticating users, your users' secure, verified user data will be available to you in your security rules via the auth variable. Let's assume that you have authenticated users and each user has a unique id, accessible via auth.uid.
For sharing group presence, I would recommend storing your data using a structure such as:
/groups/<group-id>/users/<user-id>/<presence-status>
Using this structure, you could write security rules that would make presence data globally private while user's could only view the presence state for each user in groups they're permitted to and only edit their own user's state. Here's an example security ruleset that enforces these restrictions:
{
"groups": {
"$groupid": {
// Users can view the presence state of users in this group if they
// are authenticated and listed in the group themselves.
".read": "auth != null && data.child('users').hasChild(auth.uid)"
"users": {
"$userid": {
// Users can update only their individual account data.
".write": "auth != null && $userid == auth.uid && newData.val() != null"
}
}
}
}
}
In the above example, only users in /groups/<group-id>/users/ have permission to see the presence data for the group, and each user can only modify their individual data. User can read / write only to their individual user node.
To extend this a bit further, let's say that you have a special class of users that are the only ones allowed to create groups. You could include the user's permission level when generating the authentication tokens (for the example below, we'll set isAdmin=true), and grant that special level of access using updated security rules. For example, if only certain users are allowed to create groups, you could update the .write rule under $groupid to look like:
"$groupid": {
// Only admins can create new groups.
".write": "auth != null && auth.isAdmin === true"
//...
}