I have a Firestore db with two collections: users and tournaments. The users have a 'participant' role and an 'admin' role and are indicated by 'isParticipant' and 'isAdmin' booleans in the user document:
/users/{userId}:
isParticipant: true
isAdmin: true
I have access rules set up for these collections like so:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow create, read;
allow update: if request.auth.uid == userId;
}
match /tournaments/{tournamentId} {
allow create, read, update: if request.auth.uid != null;
}
}
}
However, what I really want to do is restrict the creation of a tournament to a user that is of an 'admin' role. I am already doing this in code, but would like the added security of a db rule to prevent anyone but an admin user from creating a tournament.
Is there a way to reference the data element of a different collection within the rules syntax? Something like:
match /tournaments/{tournamentId} {
allow create: if resources.users.userId.isAdmin == true;
}
?
Thanks in advance.
You can access the data in a different collection by using the get function:
// Allow the user to delete cities if their user document has the
// 'admin' field set to 'true'
allow delete: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
For more information on this, see access other documents in the Firebase documentation, which is where I got the above example from.
One thing to note is that this requires an additional document read. If you'd store the fact that a user is an admin inside their profile as a custom claim, you could access it from request.auth without needing an extra read. E.g.
allow delete: if request.auth.token.admin == true
For more on this, see control access with custom claims and accessing the user token in the documentation.
Related
I have the following firestore setup, how can I set the rules to let only owners of marketCompra, marketTroca and marketVenda documents to delete?
The other ones I will let everybody see.
Firestore does not have a built-in concept of a "document owner". For that, your app will need to include data indicating which user "owns" the document (for example having a ownerUid field set to the Firebase Authentication UID of the user that created/owns the document) and then in your Firestore Rules you can ensure that the allow delete: condition checks the current request.auth.uid to that field's value.
service cloud.firestore {
match /databases/{database}/documents {
match /marketCompra/{docId} {
allow delete: if isOwner();
}
function isOwner() {
return request.auth.uid == request.resource.data.ownerUid;
}
}
}
For "The other ones I will let everybody see", you can simply use:
allow read: if request.auth.uid != null
meaning that as long as the user is logged in to the app, they can issue a read request against this collection (or document).
By the way, you might find this article worthy of a review: https://fireship.io/snippets/firestore-rules-recipes/
I have an application that pulls data from cloud firestore. this app does not receive user login but firestore sent me an email saying it is not secure. mail of firestore security
There seems to be a security problem in authentication, but I don't want user login.
Here are my current "Cloud firestore Rules" settings:
`
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == request.resource.data.author_uid
}
}
}`
How can I make this more secure?
Can I limit the number of reads as another solution?
The problem is, you're allowing not authenticated users to read your whole database. Another one is your authenticated users can create in your database what ever they want.
You need to restrict more access to your database. Someone will make his own database out of your database. He can create a document in a collection you expect should exist. This document will have nested collection with his database and everyone can read it. The best part is, if you have thousands of documents in your collection, you won't find that one document with nested collection easy.
To prevent that, restrict access to the whole database:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /articles/{articleID} {
allow read: if true;
allow write: if request.auth != null && request.auth.uid == request.resource.data.author_uid
}
}
}`
I am developing a small webapp based on a firestore database and I just want certain users to access (read and write) the data. It may be like 15 or 20 UIDs. I have created a collection -in root level- named "whitelist" and inside it each document has the UID of the user and several fields with the userID, userName and userEmail.
Then I have written my rules as follow:
service cloud.firestore { match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null && data.child('whitelist').hasChild(auth.uid);
} } }
However, I have tried with my own user to see if it works and the user is not able to read anything at all even though there is a document within the whitelist collection. What am I doing wrong?
// This will check if the user is authenticated and his UID exists
// in "haveAccess" collection which must be placed in root. You can use the same for ".write"
".read":"(auth !== null && data.child('haveAccess').hasChild(auth.uid))"
You can check the documentation for rules here : Google Firebase Database Rules
It is well worth to ensure that the statement data.child('whitelist').hasChild(auth.uid) returns true.
Also according to Data validation you should use resource.data
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.
You can try adding resource:
service cloud.firestore { match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null && resource.data.child('whitelist').hasChild(auth.uid);
} } }
I am trying to only allow reads to some documents if the user's uid matches the document's uid.
resource.data.uid == request.auth.uid
The security simulator gives me this errror for this line.
Error: simulator.rules line [20], column [16]. Null value error.
Is this a functionality that is just not supported by Firestore security rules?
If I understood well, I think you want something like this:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow list, create: if request.auth.uid != null;
allow get, update, delete: if request.auth.uid != null && resource.id == request.auth.token.email;
}
}
}
This code should allow users to create their own documents and access/edit only them.
Also, list allowance is required to check if the document exists before creating it, so apparently it needs to be allowed to all authenticated users.
Note that resource.id is actually the document's name. So it means that when you create a document, its name must be the user uid. And of course, you won't be able to have more than one document per collection for the same user.
I'm struggling by setting the firestore rules.
As per the screenshot, I have collection for the user with dynamic document IDs.
I'm trying to set a rule for the user to access only his/her document.
FbId is facebook id (since it is the authentication way in my app)
userId is firebase id (not sure if it is important to save it or not)
Here is my current rule:
match /users/{document=**} {
allow read, write: if normalUser();
}
function normalUser() {
return request.auth.token.firebase.sign_in_provider == "facebook.com"
&& request.auth.uid != null;
}
This rule gives access to the authenticated user for the whole collection.
How can I set this rule? If there is anything I need to change in the structure?
Update: I don't want to change the documentid for the user collection to match userid because I have another collection where the user could have multiple documents; so this solution won't fit everything.
Thanks
My get method from the app was using facebook id in the query that is why it wasn't working.
The rule I'm using right now:
match /users/{userId} {
allow update: if request.auth.uid == resource.data.userId;
}
Thanks
It will be far easier for you to use the Firebase Authentication UID of the user as the ID of the document. The Facebook UID is not going to be available in security rules.
If you use the Firebase UID, you can then write rules that look like the ones in the documentation for user-based security. Click through and read where it says "Another common pattern is to make sure users can only read and write their own data". This is probably what you want to do.
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;
}
}
}