This question already has an answer here:
Firebase firestore only allow read if user has exact document ID
(1 answer)
Closed 1 year ago.
I have a collection named proposals, which I want to disable listing on it and allow only get if user know the ID.
Is it possible with Firebase?
My currently fails because "read" is allowed, but without this I can't read the document.
match /proposals/{uid} {
allow list, update, delete: if false;
allow create, read: if true;
}
It's pretty common to do this kind of authorization, and yes, it's possible.
Firestore Security Rules provide to us request.auth.uid which contains the UID of the user making the request or null if it's unauthenticated.
So, you could use that information with an equality operator:
match /proposals/{uid} {
allow list, update, delete: if false;
// Allow getting Documents if the Document ID is equal to the currently uid of the authenticated user who is making the request.
allow get: if request.auth.uid != null && request.auth.uid == uid;
allow create;
}
You should use get to define rules that will apply when any user is trying to get a document. Note that read is for any type of read request, which includes get and list.
More about Security Rules and Authentication: https://firebase.google.com/docs/rules/rules-and-auth
Related
How do I check the document owner before allow for the user the create ?
steps:
the document is already created by the same owner.
after that the same owner will try to create property and value inside the doc.
document.owner give me error when publishing.
//only allow create in moviesCommentID/{document} when document is owned by the user
match /moviesCommentID/{document=**} {
allow create: if request.auth != null && document.owner == request.auth.uid;
}
any help is greatly appreciated.
1- Creation
You need to have a field in the Firestore Document you are changing that stores the owner uid
allow create: if request.auth != null && resource.data.ownerUid == request.auth.uid;
2- Update:
Use the same as for "create" (owner is actually the person logged), but also add something to say they cant change the owner to another user
allow update: if request.resource.data.ownerUid== resource.data.ownerUid;
Note that request.resource variable contains the future state of the document
The document variable in your rules is a string with the document ID as its value.
Firestore doesn't have any built-in concept of a document owner. But if you have an owner field in the document's data, you can access that in your rules as resource.data.owner. Also check the Firebase documentation on data validation in security rules.
I am developing a Flutter app and using Firebase as backend. In my app, each user needs o sign up to be able to use the app and the user's profile data is saved in a user_profile collection.
Each user's profile data is stored in a separate document in the collection.
The Document ID for each document is equal to the User ID, created by the Firebase Authentication when the user signs up for the first time.
And I also save the User ID in a field (named uid) in each document as well for the corresponding user.
For the security part, I want that each user may only read his/her own profile data. I set the following rule:
// Rules for User Profile data
match /user_profile/{any} {
allow read: if (request.auth != null) &&
(resource.data.uid == request.auth.uid) &&
exists(/databases/$(database)/documents/users/$(request.auth.uid));
Is it correct if I set my rules as given in the above example?
(1) The user needs to be authenticated
(2) The uid in the incoming request needs to be equal to the uid field in the corresponding document that the user wants to read.
(3) The document with the uid available in the request must exist in the corresponding document
I cannot make it clear to me if I am making the whole thing unnecessarily complicated. For instance, does the rule (1) do the same thing as rule (2)? While I have rules (1) and (2), does it add anything to have rule (3) as well?
Based on the following elements in your question:
The user's profile data is saved in a user_profile collection
The document ID for each (user's profile) document is equal to the User ID
You want that each user may only read his/her own profile data
the following read security rule should do the trick:
service cloud.firestore {
match /databases/{database}/documents {
// Match any document in the 'user_profile' collection
match /user_profile/{userId} {
allow read: if request.auth != null && request.auth.uid == userId;
// ...
}
}
}
In other words, since the document ID for each (user's profile) document is equal to the userId you don't need to use the field containing the userId in the security rule: The wildcard expression {userId} makes the userId variable available in rules, see the doc.
I am writing a chat application and am done apart from the security rules section. I am currently creating two documents for each message (one each for each user) I am okay with writing a document to my user Id but the database isn't allowing for a write in the other paired user Id.
I have tried by allowing the write if the userId is in the resource.data of the other file
match /message/{user}/{chatRoomID}/{messageId} {
allow read, write: if request.auth.uid == user || request.auth.uid in resource.data;
}
How can I make it so whenever a message is sent to the database it is only read and can be written by the specific user Ids??
Each message object has reference to who sent it (each user's object Id). Thanks in advance !!
While in is indeed an operator in security rules, this won't work:
request.auth.uid in resource.data
The in operator checks if a key exists in a map, where it is much more likely that you store the UID of the other user in the value of a field.
To check whether a certain field has a specific value, use something like this:
request.auth.uid == resource.data.senderID
I have these rules:
match /suuntoAppAccessTokens/{userName} {
allow create: if request.auth.uid != null && request.auth.token.firebase.sign_in_provider != 'anonymous';
match /tokens/{userID} {
allow read, write, create, update, delete: if request.auth.uid == userID && request.auth.token.firebase.sign_in_provider != 'anonymous';
}
}
match /{path=**}/tokens/{userID} {
allow read, write, create, update, delete: if request.auth.uid == userID;
}
That means that for the path /suuntoAppAccessTokens/dimitrioskanellopoulos/tokens/{userID} the current user should have access.
However, when I query the collection group like so:
return this.afs.collectionGroup('tokens').snapshotChanges();
I get a permission error.
Getting directly the document under tokes/{userID} works as expected.
What can I do so that the current user can run a collectionGroup query and get the items he is permitted to get based on my rules?
Your rule is expecting that the security rule will filter all the documents from all of the tokens collection so that only the current user's documents will be read. This is not possible with security rules. Security rules are not filters. From the documentation:
When writing queries to retrieve documents, keep in mind that security
rules are not filters—queries are all or nothing. To save you time and
resources, Cloud Firestore evaluates a query against its potential
result set instead of the actual field values for all of your
documents. If a query could potentially return documents that the
client does not have permission to read, the entire request fails.
You will need to change your query to that the client is only requesting documents that are fully expected to be readable by the current user. Unfortunately, it's not possible for me tell if this is possible with your current schema. The ID of the document {userId} can't be used in a collection group query to filter the documents. So, both you must ensure that both of the following criteria are met:
You will need some field in the document that you can filter on to get this job done.
You will need to adjust your security rule to match exactly what the client is asking for.
I suggest storing the uid of the user in the document with the token, the same as {userId} in the rule. You can query it like this:
collectionGroup('tokens').where("uid", "==", uid)
Be sure that the client passes in the uid correctly
Also, you will need to make sure that the rule is granting access by the exact same criteria:
match /{path=**}/tokens/{userID} {
allow read, write, create, update, delete:
if request.auth.uid == resource.data.uid;
}
This will only allow access to the document if its uid field is the same as the auth uid, which is exactly what the client is asking for.
I'm trying to set a rule so that only authenticated users can update, create, write and delete their cat documents. My problem is that I can not create a new document.
When I try to add it I get the error message "Error: Missing or insufficient permissions."
The strange part is that I can delete existing documents with this rule.
service cloud.firestore {
match /databases/{database}/documents {
match /cats/{catId} {
allow read;
allow update, create, write, delete: if resource.data.ownerId == request.auth.uid;
}
}
}
Maybe you are missing request e.g. request.resource.data.ownerId == resource.auth.uid
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
https://firebase.google.com/docs/firestore/security/rules-conditions#data_validation