Firebase Security Rules - Undefined Resource Error - firebase

I have collection Users which has documents with the same Id as the user.uid. I want to allow logged in users to create documents and only update, delete and read their documents which is specified with the same UID as mentioned.
I tried this but it keeps failing.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{document} {
allow create, : if request.auth != null;
allow update, delete, read: if request.auth != null && request.auth.uid == request.resource.data.UID;
}
}
}
In this code i am trying to compare the uid of the logged user with a document field called UID

Have a look at the documentation, it shows exactly the response to your question.
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 != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
}
}
The key point is to use the {userId} wildcard expression to match the ID of the document being read/updated/deleted with the uid of the user (i.e. request.auth.uid);

Related

Firebase security rules with users collection for Signin

I have a "users" collection to store some user data such as city, age, etc. I use firebase Authentication as a document key.
An example path is: /users/ZXHSGdhjfdfwd
I want users to read-only their data while signup/signin. So I have a rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, update, delete: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null;
}
match /posts/{post}/{document=**}{
allow read, write: if request.auth != null;
}
}
}
This doesn't work, and rules monitors show an error. As a result, users cannot sign in as I read users' collections as part of the sign-in process.
When I remove userId and change the rule to:
match /users/{userId} {
allow read: if (request.auth != null);
allow create: if request.auth != null;
}
It works, however, does that mean that userID from firestore (key) and auth.uid does not match, or one of them is null?
This is a pretty standard rule. Why is it not working?
Thanks

How can i restrict unauthenticated access to Firebase Firestore while permitting new users to add account data?

I am using firebase authentication on my reactJS application.
When a user signs up, an entry is added into firestore to store some account details at user/(UID).
I need to create firestore rules that willL
Prevent unauthenticated users from reading and writing to firestore
Only allow users to read their own data in firestore Users/(users UID)
Allow newly registered users to write to firestore so data can be added for their account.
I have tried the following:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
allow read;
allow write: if request.auth != null;
}
}
}
But i am receiving an email each day from Firebase saying my rules are insecure and anyone can write to my database.
How can i fix this?
You have a recursive wildcard (/{document=**}) with the rule allow write: if request.auth != null; which allows any authenticated user to write in any collection/document of the database. Based on the given constraint, try refactoring your rules to:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{sub=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}

Allow write based on the value of a document fileld

I want all authenticated users to read the collection but only the user with the uid that is specified in the field named uid should be able to write.
service cloud.firestore {
match /taken/{doc}{
allow read: if request.auth.uid != null;
allow read,write: if request.auth.uid == doc.id;
}
}
}
However, the above code does not allow write access even if the query has the right uid.
Try this:
service cloud.firestore {
match /taken/{doc}{
allow read: if request.auth != null;
allow create: if true; // resource.data is not defined on create, hence the separate case
allow update, delete: if request.auth.uid == resource.data.uid;
}
}
}
And you can even force the uid field to be set on create, depending on your logic:
service cloud.firestore {
match /taken/{doc}{
allow read: if request.auth != null;
allow create: if request.auth.uid == request.resource.data.uid; // Forces uid to be set to the user's uid
allow update, delete: if request.auth.uid == resource.data.uid;
}
}
}
You can read data of the document being access using resource object as explained in the documentation.
service cloud.firestore {
match /taken/{doc}{
allow read: if request.auth != null;
allow write: if request.auth.uid == resource.data.id;
}
}
}
The above rules allow any authenticated users to read the documents in 'taken' collection but only user with that UID in the documentation to write it.

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

Resources