Hi I am getting a little bit confused here with Firebase User UID and Firestore Document ID (userId???)... and looking for some help :-)
By creating a user I get a UID and I write it to the database
let db = Firestore.firestore()
db.collection("user").addDocument(data: [
"name": "confused",
"uid": result!.uid ])
by doing so I get a unique document-id (marked green) which I thought is the userId as well:
The thing I wanted to achieve is that the user can only read and write his document (green) and not the other documents (red)
Therefore I used the following rules
rules_version = '2';
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 /user/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
So the UID and the document ID (userId???) should have a connection do they? But I don't really get it?! In my app I want to retrieve the document id of the user, to use it later on a http-trigger but I can only get the UID
print(Auth.auth().currentUser!.uid)
any ideas or do I get it completely wrong?
It's normal to use the UID of the user as the ID of their own document. Right now, you are using addDocument, which tells Firestore to assign a random ID to the document. With that, the security rule will not work as expected (because the ID assigned by Firebase Auth will never match the document ID assigned by Firestore. What you should do instead is use setDocument and specify the UID from Firebase Auth as the document ID to write.
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/
Having read through the documentation, I believe the rules below should allow me to lock all documents inside a database to their respective owners. So I have a property on a document called owner, which should compare the auth uid and set permissions based on the ownership of the document. I'm still receiving an Insufficient permissions error though. Someone can explain to me why this is happening?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid == resource.data.owner;
}
}
}
Edit
Let's assume I have a task object in a todo app. All the tasks are stored in the same tasks collection: /databases/{database}/documents/tasks/*
tasks/arYBG3ydXW: {
title: 'A task',
owner: uid,
}
I want to make sure that only the owner of the document can read or edit that document. However, first error already happens when trying to read the tasks from the collection. To be clear: I created some documents without rules setup, so I was initially able to write to the database without enforcing restrictions.
query(collection(db, 'tasks'), where('owner', '==', uid))
#firebase/firestore: Firestore (9.9.3): Uncaught Error in snapshot listener: {"code":"permission-denied","name":"FirebaseError"}
Also, I'm questioning now whether this is the best way to structure my data in this scenario. What would you consider to be "best-practice", approach 1 or 2 (assuming multiple users are going to access the same database)?
Approach 1: (with a prop indicating to whom a doc belongs)
/databases/{database}/documents/tasks/*.{uid}
/databases/{database}/documents/workspaces/*.{uid}
...
Approach 2: (all docs for a user in a separate collection)
/databases/{database}/documents/uid/{tasks},{workspaces}, ...
As pointed out by Frank in the comments from the original question, looking up the UID at execution time fixes the issue.
So instead of doing this:
query(collection(db, 'tasks'), where('owner', '==', uid))
do this:
query(collection(db, 'tasks'), where('owner', '==', getAuth().currentUser.uid))
I don't know if i am able to ask this question properly, but here it goes...
I have a firebase collection, which has the bool field 'isAdmin'. So now when users are logging in, i want to set a rule to check whether this field is 'true', before allowing them access to another collection i got.
Is there a way to do it?
It sounds like you want to define access based on a value in a document about the current user. For an example of that, have a look at the documentation on attribute based access control. Based on the example there:
service cloud.firestore {
match /databases/{database}/documents {
// For attribute-based access control, Check a boolean `admin` attribute
allow write:
if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin
== true;
allow read: true;
}
}
So here each user has a document in the users collection with the document ID the same as their UID, and the rule then gets that document and checks for the specific value you want.
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;
}
}
}