I have a specific need to allow my users to create Firestore documents which match a specific structure, but to not allow those same users from updating that structure upon creation.
To put it simply, I want my users to be able to create new documents but to not update them.
I have the following security rules defined:
service cloud.firestore {
match /databases/{database}/documents {
function isAuthenticated() {
return request.auth.uid != null
}
match /conversations/{conversationId} {
function isParticipant() {
return resource.data.participants[request.auth.uid] == true
}
function NewConversation() {
// One of the participants must be the current user
return request.resource.data.participants[request.auth.uid] == true
}
allow read, delete: if isAuthenticated() && isParticipant()
allow create: if isAuthenticated() && NewConversation()
// allow update: if isAuthenticated() && NewConversation()
}
}
}
It turns out, however, that no matter how I attempt to create the document, I always get the telltale permission-denied
error. I am quite certain that the document I am trying to save contains the participants
map with the current user's Id as a key set to true
, just as the rule expects.
I can successfully create the document if I also allow update
operation by uncommenting the third rule.
Is this a Firestore bug or am I misunderstanding something?
The documentation (and the clear separation of create
and update
operations) seems to indicate that this is possible.
For completeness, this is the client request I am making which fails the test:
it('allows creating new conversations', async function() {
// clients.primary is a Firestore instance authenticated with
// the primary user used below as a key
const doc = await clients.primary.collection('/conversations').add({
participants: {
[users.primary.uid]: true,
[users.secondary.uid]: true,
},
})
})