1

Can the below security rule ensure uniqueness of firstName, lastName, username, and email before creating a document in profiles collection?

match /profiles/{document=**} {
   allow create: if request.auth.uid != null
   && (request.resource.data.firstName is string && resource.data.firstName != request.resource.data.firstName)
   && (request.resource.data.lastName is string && resource.data.firstName != request.resource.data.firstName)
  && (request.resource.data.username is string && resource.data.username != request.resource.data.username)
  && (request.resource.data.email is string && resource.data.email != request.resource.data.email)
}

For example, below is the data in Firestore collection profiles

{
   "document1":{
      "firstName":"Jek",
      "lastName":"Choo",
      "email":"jeksomething@gmail.com",
      "username":"jek"
   },
   "document2":{
      "firstName":"Cara",
      "lastName":"Choo",
      "email":"babycara@gmail.com",
      "username":"cara"
   }
}

I want to create the below new document, and this create access should be denied

{
   "document3":{
      "firstName":"Jek",
      "lastName":"Choo",
      "email":"jeksomething@gmail.com",
      "username":"jek"
   }
}

And I want to create the below new document, this should be allowed.

{
   "document4":{
      "firstName":"example",
      "lastName":"com",
      "email":"test@example.com",
      "username":"example"
   }
}

In conclusion, can the above firestore security rule help to ensure field value uniqueness before a document is allowed to be created?

Jek
  • 5,546
  • 9
  • 37
  • 67
  • 1
    AFAIK there is no direct API to check if collection already have a document with same values before posting new document to cloud store collection. But there is another one method with which you should query over all the documents of collection to check if there is already one and this can be done with [where()](https://firebase.google.com/docs/firestore/query-data/queries) which takes three parameters: a field to filter on, a comparison operation, and a value. – Mohammed Farhan Dec 20 '18 at 05:33
  • Thanks but your solution is client-side validation before creating a new document. Firestore security rule is server-side validation before creating a new document. This is important. – Jek Dec 20 '18 at 05:38
  • Okey, [here](https://stackoverflow.com/questions/52016426/firestore-security-rule-to-check-if-character-username-already-exists) you can read answer of `Frank van Puffelen` Engineer from Firebase on this topic. I think this cant be done with only security rules. – Mohammed Farhan Dec 20 '18 at 05:55

1 Answers1

5

It's important to understand what resource does with respect to rules that create new documents, which is the only rule you're showing here.

resource refers to "the (existing) document being written". This is in contrast with request.resource which describes the document that doesn't yet exist, that is about to exist, if the write succeeds.

To put it another way, in this section:

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.

In the case of a create, there is no existing document being written. Therefore, you can assume that any matches against resource to fail. Therefore, this will not ensure uniqueness.

In fact, you can not ensure uniqueness of any given document field for a create, since it's not possible in security rules to query all documents in the collection for existence for that field.

The only form of uniqueness observed by Firestore is that of the id of a document within a collection. All fields of that document can not be constrained to be unique by security rules, and there are no indexes in Firestore that ensure uniqueness.

If you need a field to be unique, you should check after the document creation by using Cloud Function trigger, then delete the document if it doesn't satisfy the requirements.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441