Search code examples
google-cloud-firestorefirebase-security

Firestore rules depending on document attribute


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}, ...

Solution

  • 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))