Firestore rules : User access to a collection that contain userId - firebase

I have 2 collections in my Firestore
users : uid, email
periods : periodId, name, owner_id
I need rules for users access only to it's 'users' collection and another that allow read and write to 'periods' collection only if ownerId uid is equal to authentified user id.
I do that
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write : if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
match /periods/{periodId} {
allow read, write : if request.auth.uid == request.resource.data. owner_id;
}
}
}
But it doesn't work.
:(

You don't share the queries corresponding to these security rules, but we can already identify several problems in your Security rules:
1. For /users/{userId} you have some overlapping between create and write.
The following shall solve this problem:
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
See the doc: "In the case where multiple allow expressions match a request, the access is allowed if any of the conditions is true".
2. For /periods/{periodId} you need to split between read and write.
For read access rights, the resource variable refers to the
requested document, and resource.data is a map of all of the fields
and values stored in the document.
For write access rights the request.resource variable contains the
future state of the document.
(source)
So the following should do the trick (untested):
match /periods/{periodId} {
allow read : if request.auth.uid == resource.data.owner_id;
allow write : if request.auth.uid == request.resource.data.owner_id;
}
I would suggest you watch the following official video on Security Rules. Actually the entire "Get to know Cloud Firestore" video series is a must...

Related

How to set rules in firebase firestore and realtime?

In firebase firestore:
I have a three different collections, 1:- "users", 2:- "ContactUs", 3rd "Reports".
In users, document is created by uid and then it has a field inside by the name of "uid".
In ContactUs and Reports, document is generated randomly and it is different every time.
I have tried the following rules but I am not sure about it, pls help me to correct it. In ContactUs and Reports, is there should be {userId} or something else as it is different each time and how I am going to compare it with uid as there is no field of uid inside them?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow write, update, delete: if
request.auth.uid == userId;
allow read: if request.auth.uid != null;
}
match /ContactUs/{userId} {
allow write, update, delete: if
request.auth.uid == userId;
allow read: if request.auth.uid != null;
}
match /Reports/{userId} {
allow write, update, delete: if
request.auth.uid == userId;
allow read: if request.auth.uid != null;
}
}
}
In realtime database: I have attached a photo for reference which shows details of child created at the time of users starts new chat.
I have tried the following rules in realtime but it says:- Your security rules are not secure. Any authenticated user can steal, modify, or delete data in your database.
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Pls help me to set them correctly. Thanks.
Firestore rules work same as code CSS. It reads from up to bottom and rule below can overwrite rule before. So first you should restrict access to whole database.
This rule should be at the top of all rules.
match /{document=**} {
allow read, write: if false;
}
write word is equal to all words together create, update, delete so use those words separatly for diferent conditions or just write word.
If i whare you i would make rules for users collection like this:
match /users/{userId} {
allow create, update: if
request.auth != null && request.resource.id == request.auth.uid;
allow read: if request.auth != null && userId == request.auth.uid;
}
In example above user can create/update document if his request document has same id as his uid and can read if document id he request is equal to his uid. In this rules there are no delete operation so he will cant delete his document.
realtime database works really similar but you have to get to know on your own how to make rules.

How to manage rights in firebase to allow differents users to read/upate/write?

I've a firestore database and I now need to add a new collection.
Each entry of this collection should contain:
Which userId is the owner(field admin)
Which userId has been allowed to edit this element(field writer)
Which userId has been allowed to only read(field reader).
I'm currently only at the first step, and already strugling:
I was hoping to be able to query my collection( /trips/) and get only the one that I'm allowed to access, but I get an error:
FirebaseError: Missing or insufficient permissions.
Here is my rules file:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
match /trips/{trip} {
allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.admin;
allow create: if request.auth != null;
}
}
}
So my questions:
Is this the correct way of managing resource that must be acceeded by multiple people(meaning, I cannot just have the userId in the path since there are multiple users)
How should I query only the documents list that I'm allowed to see?
Thank you very much for your help
As you will read in the doc, "All match statements should point to documents, not collections".
With
service cloud.firestore {
match /databases/{database}/documents {
match /trips {
// ....
}
}
}
you don't point to a document. You should use a wildcard to point to any document in the specified path, as follows:
service cloud.firestore {
match /databases/{database}/documents {
match /trips/{trip} {
// ....
}
}
}
Therefore the following should correctly implement your requirements:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /trips/{trip} {
allow read: if request.auth != null &&
(request.auth.uid == resource.data.admin
|| request.auth.uid == resource.data.writer
|| request.auth.uid == resource.data.reader
);
allow update: if request.auth != null &&
(request.auth.uid == resource.data.admin
|| request.auth.uid == resource.data.writer
);
allow create: if request.auth != null;
}
}
}
Then, for the two questions:
Is this the correct way of managing resource that must be acceeded by multiple people (meaning, I cannot just have the userId in the path
since there are multiple users)
If the admin, writer and reader are specific for each document, yes this is the correct way. If those roles would be more global (e.g. all the trips to Europe can be edited by the same user), you could use a role based approach with Custom Claims.
How should I query only the documents list that I'm allowed to see?
It is important to note that rules are not filter. So your query for getting docs needs to be aligned with the rules. In your specific case, you could have an additional field of type Array which contains three values; the uids of the admin, writer and reader, and use the array-contains operator. Something like:
const user = firebase.auth().currentUser;
const query = db.collection("trips").where("authorizedReaders", "array-contains", user.uid);
match /{document=**} {
allow read, write: if false;
}
You don't need the above code as it will apply to all routes of the database, because of the above line you are getting the below error as it does not allow you to read and write to the database
FirebaseError: Missing or insufficient permissions.
Now, if you want to assign privileges to users then you should add the Role field to users collections which would have a value such as Admin, Editor, Reader
Then, you can check in routes something like below
match /users/{userId}/trips/{tripId} {
allow read, delete: if request.resource.data.role == "Admin";
allow create, update: if request.resource.data.role == "Admin || request.resource.data.role == "Editor";
}
If you want to know more about how to create a route check out this video for the best explanation

Firebase Cloud Database Rules - how to retrieve data only where the user id matches a key in the object?

Is there a way using firebase rules to retrieve all the projects that have a specific "userID" value. I tried reading all the rules and came up with this rule but they do not work:
I only want to read the documents which matches auth.uid == userID in database.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Allow public read access, but only content owners can write
match /debtors/{userID}/{documents=**} {
allow read: if request.auth.uid != null && request.auth.uid == userID;
allow create: if request.auth.uid != null;
allow update, delete: if request.auth.uid != null && request.auth.uid == userID;;
}
}
}
I have the following object in collection:
{firstname: "Aacis"
relation: "friend"
userID: "7ScK2T0T3SMUR1NJxjiCiRzTnm62"}
Fetching stream in flutter with:
stream: Firestore.instance
.collection("debtors")
.where("userID", isEqualTo: user.uid)
.snapshots()
Did you set auth.uid as document id, and object key named userID?
Firestore.instance.collection("debtors").doc("7ScK2T0T3SMUR1NJxjiCiRzTnm62").set({
firstname: "Aacis",
relation: "friend",
userID: "7ScK2T0T3SMUR1NJxjiCiRzTnm62"
})
If you want to allow only onwer to read access to then you should set allow read: if request.auth.uid != null && request.auth.uid == userID;
If you want to read the documents which matches auth.uid == resource.data.userID then you should set allow read: if request.auth.uid != null && request.auth.uid = resource.data.userID;
If you want to allow public to read access then you should set allow read: if true;
And More, A read rule can be broken into get and list.
service cloud.firestore {
match /databases/{database}/documents {
// A read rule can be divided into get and list rules
match /cities/{city} {
// Applies to single document read requests
allow get: if <condition>;
// Applies to queries and collection read requests
allow list: if <condition>;
}
// A write rule can be divided into create, update, and delete rules
match /cities/{city} {
// Applies to writes to nonexistent documents
allow create: if <condition>;
// Applies to writes to existing documents
allow update: if <condition>;
// Applies to delete operations
allow delete: if <condition>;
}
}
}
See:
https://firebase.google.com/docs/firestore/security/rules-conditions
https://firebase.google.com/docs/firestore/security/rules-structure#granular_operations
https://firebase.google.com/docs/reference/rules/rules.firestore.Resource
Updated
A userID in the following code means the document id is auth.uid, and allow only onwer to read access.
match /debtors/{userID}/{documents=**} {
allow read: if request.auth.uid != null && request.auth.uid == userID;
So you don't set auth.uid as document id, and the stored value named userID in the document match auth.uid, you should use resource.data.userID and request.resource.data.userID.
Please try the following code.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /debtors/{document=**} {
allow read: if request.auth.uid != null && request.auth.uid == resource.data.userID;
allow create: if request.auth.uid != null && request.auth.uid == request.resource.data.userID;
allow update, delete: if request.auth.uid != null && request.auth.uid == resource.data.userID;
}
}
}
The resource variable refers to the requested document, and resource.data is a map of all of the fields and values stored in the document. For more information on the resource variable, see the reference documentation.
When writing data, you may want to compare incoming data to existing data. In this case, if your ruleset allows the pending write, the request.resource variable contains the future state of the document. For update operations that only modify a subset of the document fields, the request.resource variable will contain the pending document state after the operation. You can check the field values in request.resource to prevent unwanted or inconsistent data updates:
See:
https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation
https://firebase.google.com/docs/reference/rules/rules.firestore.Resource
https://firebase.google.com/docs/reference/rules/rules.firestore.Request#resource

Cloud Firestore Security Rules documentation example

This documentation page: Writing conditions for Cloud Firestore Security Rules, says the following:
Another common pattern is to make sure users can only read and write their own data
And provides this example:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
I don't understand why the create rule is not defined with the same condition as the rest, if request.auth.uid == userId, but instead is defined with if request.auth.uid != null. As I understand it, with this rule any user can create any document inside users, but cannot do anything with it unless it matches his uid. So why allow it at all?
Let's talk about the very basic security rule that could be implemented (with user authentication):
allow read, update, delete: if request.auth.uid != null;
allow create: if request.auth.uid != null;
where any user can delete the documents of another people creation. So to restrict/control it, we implement as shown in the code snippet provided.
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
The code snippet is just an example use case that uses different conditions for reference purposes as this is a tutorial/guide, so the Firebase team try to fit as many possible conditions to the code snippet.
You can, of course, do allow create: if request.auth.uid == userId; to strictly restricted to that particular user.
I hope it gives you some idea!

Firebase database rules: cant read an another collection

can you help me please?
I have these rules
service cloud.firestore {
match /databases/{database}/documents {
match /locations/{document=**} {
allow read, write;
}
match /Users/{userId} {
allow read: if request.auth.uid != null && request.auth.uid == userId;
allow write: if request.auth.uid != null && request.auth.uid == userId;
}
}
}
So when I am trying to access the 'locations' collection via Firebase Simulator I get an error:
Simulated data access denied
Here is a
screenshot
The path in the Location field of the Simulator is
/databases/(default)/documents/locations
I CAN access and write a data to the Users collection from my app (when authorized of course) but the problem is that I need to allow the access to the Locations collection without any permissions. I can't read a 'locations' collection
Any advice highly welcome
The path you are specifying is incorrect.
It should be only locations/documentID instead of databases/(default)/documents/locations/documentID.
/databases/(default)/documents is basically a tooltip of where you are.

Resources