I have below data stored in my firebase:
firebaseRoot
admins
simplelogin:1:
users
simplelogin:1
email: abc#xyz.com
picture: csd
provider: password
uid: simplelogin:1
simplelogin:2
email: abc1#xyz.com
picture: zsd
provider: password
uid: simplelogin:1
and following security rules:
{
"rules": {
"admins": {
".read": "root.child('admins').child(auth.uid).val() === true",
".write": "root.child('admins').child(auth.uid).val() === true"
},
"users": {
"$user":{
".read": "$user === auth.id || root.child('admins').child(auth.uid).val() === true",
".write": "$user === auth.id"
}
}
}
}
My authorization requirements are as below.
admins can be read and added only by the existing admin only. This works.
All users can be read by the admin but should not be able to write user data.
a user can read and update his own user data.
Currently with above rules, I am not able read users data both for admins and logged in users. I get below error message. Please provide your help. Thanks.
var rootRef = new Firebase('https://xxxxx.firebaseio.com/');
var users = rootRef.child('users');
users.on('value', function(snap) {
console.log(snap.key(), snap.val());
}, function(error) {
console.log(error);
});
Error:
Error: permission_denied: Client doesn't have permission to access the desired data.
There are two pitfalls when it comes to Firebase security rules:
rules cascade
This means that once you give somebody (read or write) access on a certain level in the JSON structure, you cannot take that right away anymore on a lower level
rules are not filters
This means that you can only read a node if you have read access to all data in that node. If you only have read access to part of the data, a read operation for the complete data will fail.
In your security rules, you only give permission to read (some of) the children under users. So trying to read the entire users.on('value' will fail.
You can solve this by giving the administrator .read access to the users node.
"users": {
".read": "root.child('admins').child(auth.uid).val() === true",
"$user":{
".read": "$user === auth.id",
".write": "$user === auth.id"
}
}
Here is my working example:
ajsecuretest
roles
simplelogin:1
role: 'admin'
simplelogin:2
role: 'editor'
users
simplelogin:1
email: 'abc#xyz.com'
picture: 'a.jpg'
provider: 'password'
uid: 'simplelogin:1'
simplelogin:2
email: 'xyz#abc.com'
picture: 'b.jpg'
provider: 'password'
uid: 'simplelogin:2'
Rules:
{
"rules": {
"roles":{
".read": "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
".write": "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
"$id" : {
".read" : "$id === auth.uid"
}
},
"users": {
".read" : "root.child('roles').child(auth.uid).child('role').val() === 'admin'",
"$user":{
".read": "$user === auth.uid",
".write": "$user === auth.uid"
}
}
}
}
Related
I have a mobile application which reads the data from the firebase server without firebase login/authentication (posts and news) and I want to create an admin webpage where I can log in and add, or modify news, so I need a write permission there. My rules are currently:
{
"rules": {
".read": true,
".write": "auth !== null && ?????
}
}
Can I write something like "user.emailAddress == 'mail#example.com'"?
You can create a users table on database like
{
"users":{
"your UID":{
"isAdmin": true
}
}
}
Then edit rules :
{
"rules": {
".read": true,
".write": "auth.uid != null && root.child("users").child(auth.uid).isAdmin === true"
}
}
You might want to start by reading the documentation about securing user data. There is a lot to know here.
One possibility is using the known user's uid to restrict access. The auth.uid variable contains the uid.
".write": "auth.uid == 'the-known-uid'"
Also you can use auth.token to access some other things about the user, including email address (which may not be present):
".write": "auth.token.email == 'the#email.address'"
You can also use custom authentication tokens, which also is covered in the documentation.
Create database:
{
"users":{
"your UID":{
"isAdmin": true
}
}
}
Set rules:
Wrong:
{
"rules": {
".read": true,
".write": "auth.uid != null && root.child("users").child(auth.uid).isAdmin === true"
}
}
Right:
{
"rules": {
".read": true,
".write": "auth.uid != null && root.child('users').child(auth.uid).child('isAdmin').val() === true"
}
}
I'm new to using Firebase (I'm using react-redux-firebase, but not sure if that's relevant to this question). I'm having an issue using these standard auth rules:
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
This is user UID as shown in the Firebase Authentication dashboard:
But if I print out the data associated with the profile/account, I get this UID:
Because of this mismatch, the logged in user is unable to read or write to the firebase instance.
Why is there a mismatch in UIDs? How can I solve this issue?
UPDATE:
It looks like the 1091103… UID is provider-specific and not relevant in this case? Can't confirm that for sure.
This may be the actual auth UID (I'm new to this, so still trying to figure out what's what):
In this case, this UID matches what is seen in the Firebase console. If they match, then what would be the cause of the permission denied errors?
ANOTHER UPDATE:
Here's the user node. You can see the UID as the key:
This is the rule you can do right now
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
if you want to check like below
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
you need to store the users to realtime database while register. with their auth.uid as key.
I am trying to access custom fields in my auth for controlling access to my data in firebase, The users field in firebase looks like this
users: {
email: string,
isAdmin: boolean,
name: string
}
I have this rules for ensuring that only admin can read the entire table of orders
"orders":{
"$userOrders": {
".read": "$userOrders == auth.uid || auth.isAdmin == true",
"$eachUserOrder": {
".read": "$userOrders == auth.uid || auth.isAdmin == true",
".write": "!data.exists()"
}
},
".read": "auth.isAdmin === true"
},
In the simulation if I pass this as part of the token it works,
{
"provider": "anonymous",
"uid": "559a9195-e2ab-4039-91ac-877d2afca482",
"isAdmin": true
}
But for users with the field isAdmin set to true on the browser it says permission denied.
util.js:233 FIREBASE WARNING: Exception was thrown by user callback. Error: permission_denied at /orders: Client doesn't have permission to access the desired data.
I don't understand what is wrong at this time.
I've database structure like
appointments
[$userId]
[$appointmentId]
message:"something"
date:"14/12/2015"
users
[$userId]
name: Hardik
email: hardikmsondagar#gmail.com
And I'm using angularfire library of Firebase, I'm trying to restrict read operation based on uid ( means a person who created appointment only can read that). I've tried following security rule
{
"rules": {
"appointments": {
"$userId":{
"$appointmentId":{
".read": "auth.uid==$userId",
".write": true
}
}
},
"users": {
"$userId":
{
".read": "auth!=null && $userId === auth.uid",
".write": "auth!=null && $userId === auth.uid"
}
}
}
But end up on this error
Error: permission_denied: Client doesn't have permission to access the desired data.
I'm trying to access all the user's appointments using following code
var ref = new Firebase("https://<FIREBASE-APP>.firebaseio.com/appointments/"+uid);
$scope.appointments = $firebaseArray(ref);
Set rules for the $uid wildcard, to read all the children.
"appointments": {
"$uid":{
".read": "auth.uid == $uid",
".write": "auth.uid == $uid",
}
}
The $uid wildcard sets permissions for the entire list, whereas the $appointmentId wildcard sets permissions for each individual item.
But Security Rules cascade, so you only need to set the rules for the top level.
Read the docs on cascading for more information.
I use Firebase $authWithPassword method for user login. I use the $createUser method to create registration for my users and on its success I update entry on my /users/ path to save the username, uid and some other details. Here is the code
var myDataRef = new Firebase(baseURL + 'datalog/');
var refObj = $firebaseAuth(myDataRef);
refObj.$createUser({
email: $scope.emailId,
password: $scope.password
}).then(function(userData) {
var UserUniqueUrl = new Firebase(baseURL + 'users/' + userData.uid + '/');
UserUniqueUrl.set({
'email': $scope.emailId,
'username': $scope.username,
'uid': userData.uid,
'theme': 'default'
}, function(error) {
if (error) {
console.log(error);
} else {
console.log('Successfully updated in user table');
}
});
}).catch(function(error) {
if (error.code == 'EMAIL_TAKEN') {
$scope.regStatusError = 'Email already registered!';
} else {
$scope.regStatusError = 'Unable to register! Try again later.';
}
});
And here is my security rules
{
"rules": {
"users": {
".read": "auth != null",
".write": "auth != null"
}
}
}
Now if I try to register it gives me permission denied error which I'm sure is because of the security rules ".read": "auth != null" and ".write": "auth != null". If I change the rules to ".read": true and ".write": true, the registration will work but anyone will be able to see my user data including uid and email id which I don't want to happen. How do i change my rules to fit my need?
This is how my user table will look like
Any help is appreciated.
Thanks.
All you want is to only allow creating a user in your firestore database when the user is authenticated:
match /users/{uid} {
allow create: if request.auth.uid != null;
}
However, you can go a head to verify the user's email as:
match /users/{uid} {
allow create: if request.auth.uid != null
&& request.auth.token.email_verified == true
}
Please note that uid will match your IDs of your documents.
yeah, you need to change your rules to something like this
{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
this should fix it