I'm looking for some advice or a possible solution with tightening up my firebase rules.
This is my user tree in Firebase:
users
|_male
|_uid
|_female
|_uid
The UID will be an epoch timestamp when the account is created which will be a signed integer.
These are the firebase rules which basically ensures the user has logged in and authenticated with Facebook before they can read or write to users:
"users": {
"male":{
".indexOn": ["uid"]
},
"female":{
".indexOn": ["uid"]
},
".read": "auth != null && auth.provider === 'facebook'",
".write": "auth != null && auth.provider === 'facebook'"
},
I only want users to read/write to their tree, for example:
users->male->uid->1233254...
I'm afraid with my rules above, they could potentially read and write from/to another users tree.
It would be great if I could compare the app UID with the Facebook UID.
I do capture this detail in another tree on the database e.g:
user_fbuid
|_fbuid
|_facebook:a1244dxs
|_uid
I do have better rules here that check against auth.uid:
"user_fbuid": {
"fbuid":{
"$fbuid": {
".indexOn": ["fbuid"],
".read": "$fbuid === auth.uid && auth.provider === 'facebook'",
".write": "$fbuid === auth.uid && auth.provider === 'facebook'"
}
},
},
If anyone has any ideas, I'd love to hear. Thanks
I ended up using the facebook id attribute as my own uid and the rules below:
"$uid": {
// only the user can read and write to their tree
".read": "auth != null && auth.provider === 'facebook' && auth.token.firebase.identities['facebook.com'][0] === $uid",
".write": "auth != null && auth.provider === 'facebook' && auth.token.firebase.identities['facebook.com'][0] === $uid"
},
Related
I'm trying to create a rule for create/access the FRD data based on authenticated user. But am getting an error where running the Rules Playground
What I want is, Users are creating the categories. So Users is able to only read their categories and update those categories.
Rule:
{
"rules": {
"users": {
"$uid": {
".write": "auth != null && $uid === auth.uid",
".read": "auth != null && $uid === auth.uid"
}
},
"categories": {
"$uid": {
".write": "auth != null && $uid === auth.uid",
".read": "auth != null && $uid === auth.uid"
}
}
}
}
Auth Users:
Realtime Database
Categories
Users
Categories Write function in Flutter
String uId = await userId();
final databaseRef = FirebaseDatabase.instance.ref('categories');
var data = await databaseRef.get();
var index = data.children.length;
await databaseRef.child('$index').set(<String, dynamic>{
"name": categoryBody.name,
"description": categoryBody.description,
"uid": uId,
"id": index,
});
Error
Is there anything wrong with the rules that am applying?
I tried to replicate your issue, but I can able to successfully test rules without errors.
The rules you are using are for authenticated users but you are testing for unauthenticated users. Means you have not enabled Authenticated field.
And you have to enter /categories/uid instead of /categories under the location and you should enter uid under Firebase UID field. You may have look at below screenshot.
You can refer this tutorial for more information.
When you're using the following security rules:
"categories": {
"$uid": {
".write": "auth != null && $uid === auth.uid",
".read": "auth != null && $uid === auth.uid"
}
}
It means that you allow the user to write/read to/from every child that exists under your categories/$uid node. So when you try to apply those rules to your actual database structure, it's the expected behavior to see that Firebase servers reject the operations since it doesn't find any $uid level in your database schema. To solve this, you have to remove that extra $uid level from rules like this:
"categories": {
".write": "auth != null",
".read": "auth != null"
}
And this is because those category objects exist directly under the categories node and not under categories/$uid.
I have a firebase database rule to block:
non-authenticated users
users trying to create data for some other user
I also want to prevent updating data.I need this code for that:
!data.exists() || !newData.exists()
This is currently how it looks:
"rules": {
"orders": {
"$order":{
".read": "auth != null && auth.token.admin === true",
".write": "auth != null && auth.uid === newData.child('userID').val()" // check the incoming data's userID value here if sender is same. or someone can send orders with other peoples ids. also anyone can send an order with id 123 but only if it doesnt exist. so they cannot update anyones order. is this safe enough?
},
".indexOn": "userID"
}
}
How am I supposed to include this "||" operator in my logical expression for the ".write" rules?
I am not able to delete data. Is it because Im checking the newData's child in the security rules and there is no newData when using ".remove()" in the app? If that is the case, how does write and delete rules in the same line work?
I got a weird issue that I could not use parantheses at first but it is now working. I created an || between two expressions
First expression is for write:
(auth != null && newData.exists() && auth.uid === newData.child('userID').val() && !data.exists())
Here "newData.exists()" in the expression tells us there is an incoming data ( write/update operation) and "!data.exists()" blocks updating data.
Second expression is for deleting rules:
(!newData.exists() && auth != null && auth.uid === data.child('userID').val()
Here "!newData.exists()" says that there is no new data so this is a delete operation, and the next part makes sure everyone can only delete their own data.
So now the code looks like this:
"rules": {
"orders": {
"$order":{
".read": "auth != null && auth.token.admin === true",
".write": "(auth != null && newData.exists() && auth.uid === newData.child('userID').val() && !data.exists()) || (!newData.exists() && auth != null && auth.uid === data.child('userID').val())"
},
".indexOn": "userID"
},
}
I am trying to create new user after I login with facebook/google, but getting error with:
error_handler.js:46 EXCEPTION: Uncaught (in promise): Error:
PERMISSION_DENIED: Permission deniedErrorHandler.handleError #
error_handler.js:46next # application_ref.js:291schedulerFn #
async.js:89SafeSubscriber.__tryOrUnsub #
PERMISSION_DENIED: Permission denied
my rules are:
"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 Facebook
".read": "auth !== null && (auth.provider === 'facebook' || auth.provider === 'google')"
}
}
when I remove my rules all works ok.
My code is:
private createNewUser(user: any): any {
const newUser = this.af.database.object('users/' + user.uid);
newUser.set({
username: user.name,
email: user.email,
profile_picture: user.avatar,
provider : user.provider,
create_date: new Date().toISOString().slice(0, 10).replace(/-/g, "")})
}
what fileds do i need to check?
You have mistake in your rules.
You allow write access only for existing users who already has uid under users/uid node but it you do not allow write access on users node.
You need to allow write access under users node. But this will cascade, which means that none of the .write rules under users node will be checked if .write rule under users node will evaluate to true. So you need to change your existing .write to .validate.
"users": {
// Grant every logged in user to write here
".write": "auth !== null",
"$uid": {
// .validate rule will restrict .write if current user id does not match the key ($uid)
".validate": "auth !== null && auth.uid === $uid",
// grants read access to any user who is logged in with Facebook
".read": "auth !== null && (auth.provider === 'facebook' || auth.provider === 'google')"
}
}
For more information about how to setup your security rules, read the following link and watch the video on this link.
https://firebase.google.com/docs/database/security/
Finally I use this rules for users.
"users": {
"$uid": {
// grants write access to the owner of this user account whose uid must exactly match the key ($uid)
".write": "!data.exists() || auth.uid === $uid",
// grants read access to any user who is logged in with Facebook
".read": "auth !== null && (auth.provider === 'facebook' || auth.provider === 'google')"
}
}
Are these rules in correct format? When I put them in Database Rules, I see red dashed lines which may indicate an error/warning but when I hover over it, I receive no feedback.
{
"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 --&& auth.provider === 'password'
".read": "auth !== null"
}
},
"usernames": {
"$userName": {
// grants write access to the owner of this user account whose uid must exactly match the key ($uid)
".write": "root.child('usernames').child($userName).child('uid').val() == auth.uid || root.child('usernames').child($userName).child('uid').val() == null",
// grants read access to any user who is logged in --&& auth.provider === 'password'
".read": "auth !== null"
}
},
"following": {
"$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 --&& auth.provider === 'password'
".read": "auth !== null"
}
},
"followedBy": {
"$fid": {
"$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 --&& auth.provider === 'password'
".read": "auth !== null"
}
}
}
}
}
This is what I see:
To reformat your code rules and make it read able
Just copy your rules and then go to JS cleaner and click claen Js re copy and past into your database rules
I've seen those too. Pretty much as soon as I add an empty line.
I think the empty lines are just causing a false error indicator to show up.
Since nothing's failing (at least not for me as far as I can see), I wouldn't worry about them.
So I have this db structure:
Under profile I want email & provider-name to be readable only for admin and
Username readable for every logged in user.
How I can achieve that?
Here is my 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",
"profile":
{
// grants read access only for registered users
".read": "auth !== null",
"email":
{
// This doesn't work with firebase as I was reading doc.
".read": false
}
}
}
}
}
}
So after a bit of research and reading about denormalize structure I guess this way will work. The fact is that I'm tempted to nest, but probably is a bad idea on firebase.
{
"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",
"public-profile":
{
// grants read access only for registered users
".read": "auth !== null"
}
}
},
"private-profile":
{
"$uid":
{
".read": "root.child('users').child(auth.uid).child('role').child('admin').val() === 'true' && root.child('users').child('1').child('role').child('admin').val() === 'true'",
".write": "root.child('users').child(auth.uid).child('role').child('admin').val() === 'true' && root.child('users').child('1').child('role').child('admin').val() === 'true'"
}
}
}
}