Kamal
Kamal

Reputation: 395

firestore security rules: allow logged in user to update field

I have the following firestore security rules

match /users/{user} {
  allow read: if request.auth != null;
  allow create: if request.resource.id == request.auth.uid;            
    
  match /replies {
    allow update: if request.auth != null;
  }
}

my understanding from the firestore security rules doc is that the two rules are independent of each other. However, a logged in user gets a permission denied message when trying to update the /user/{user}/replies field. It doesn't matter if I nest the rule or not. It still gets denied. (it also doesn't work in Rules Playground in Firebase console)

what am I doing wrong?

my client code is as follows:

const processNewMessage = async (evt, newMessage) => {
  myMessage.value = myMessage.value.trim();

  if (evt.srcElement.textContent === "send") {
    if (replying.value === true) {
      const message = {
        originalMessage: {
          text: props.selectedMessage.text,
          photoUrl: props.selectedMessage.photoUrl,
        },
        reply: {
          user: uid,
          userDisplayName: auth.currentUser.displayName,
          userName: userName.value,
          text: newMessage,
          createdAt: Timestamp.now(),
          g: { geohash: geohash.value, geopoint: myLocation },
          photoUrl: photoUrl,
        },
      };

      await updateDoc(doc(db, `users/${props.selectedMessage.user}`), {
        replies: arrayUnion(message),
      });
    }
  }
}

Upvotes: 0

Views: 645

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598623

Security rules work on a document-level. Your code is trying to update the replies array in the users document, which is not allowed by any of your rules.

The match /replies in your rules applies to a replies subcollection under the users document. It has no effect on fields in the users document.


If you want the owner to update their entire document, and other signed in users to only update the replies field, you'll have to allow that in the rule on users.

Something like this:

match /users/{user} {
  allow read: if request.auth != null;
  allow create: if request.resource.id == request.auth.uid;            
  allow update: if request.auth != null && 
    request.resource.data.diff(resource.data).affectedKeys().hasOnly(["replies"])
  ;
}

For more on how this works, see the release notes for the map diff function.

Upvotes: 3

Related Questions