Understanding Cloud Firestore Security Rules

Understanding Cloud Firestore Security Rules

Cloud Firestore improved on many things over its predecessor, Realtime Database. One of which is security. Cloud Firestore’s security rules are more flexible and easier to write than those of the Realtime Database, especially without the trouble of cascading rules.

Read on and I’ll let you decide for yourself which set of rules you find easier to write and manage.

In my last post about Why Every Developer Needs a Blog, I touched upon Soft Skills. I still can’t recommend it enough. I’m almost at the end of the book and it’s already changed my life. It’s a software developer’s life manual split into sections of Career, Marketing, Productivity, Learning, Finance, Fitness, and Spirit.

The Basics: Match and Allow

a basic example of security rules

Match points to a document you want to write your security rules for. Note that match only works with documents, not collections. There is a way to point to all documents in a collection with wildcards, but more on that later.

Allow sets the actual rule. You should always include a condition with allow statements, even if it’s just a simple if true.

Multiple Match Statements

It’s possible for a document to have more than one match statement. In this case, access will be allowed if any of the allow conditions are true. In the example above, all read and writes to the /cities/{city} path are allowed because the second statement returns true, even though the first statement returns false.

Different Allow Operations

With Firestore’s Security Rules, we have more flexibility than just read and write.

Read can be split into get and listGet refers to operations of retrieving a single document, while list refers to operations that retrieve groups of documents by querying their collections.

Write can be split into createupdate, and delete. I don’t think I need to explain each of them.

More Complex Conditions

We won’t only be writing true and false all day. We have the variables request and resource, and functions exists and get.

Request

Field Description
 auth Refers to the authenticated user and any corresponding data
 path Refers to the path that a https://firebase.google.com/docs/firestore/reference/security/authrequest is being performed against.
 query Contains the static properties of a query being requested.
 resource Contains data and metadata about the document being written.
 time Contains a timestamp representing the current server time a request is being evaluated at.
 writeFields Contains a list of the field paths that the current request is updating.

To make it a little clearer, here’s an example.

Resource

Resource refers to a document. It contains a map of the values stored in the document in resource.data.

It also contains metadata such as the document name and id, often prefixed with __, as with __name__ and __id__.

Note that this is different from request.resource in that this resource contains the data for the document at the requested path while request.resource contains the data of the document being written.

Exists

Takes in a path and returns true if a document exists at the specified path. Tha path provided must always begin with /databases/$(database)/documents.

Get

Takes in a path and returns the document at the specified path. Again, the path provided must always begin with /databases/$(database)/documents.

Hierarchical Data and Wildcards

A security rule will only apply to the matched path. These rules won’t cascade to paths above or below the matched path. You have to explicitly define rules for any subcollections. In this case, say we want to define a set of rules for paths cities/{city} and cities/{city}/landmarks/{landmark}.

Note that here, we’re nesting match statements. The path of the inner match statement is relative to the path of the outer match statement.

Recursive Wildcard Syntax: Matching all paths below

Of course, if we were to have many different subcollections that extends deep into the hierarchy, explicitly defining rules for each one of them can be very tedious. To match all the documents below a given path, use the wildcard syntax {name=**}.

What about Indexes?

If you know anything about the Realtime Database’s Security Rules, you’ll know that it has one “security rule” that doesn’t have anything to do with security: indexOn. We can still manage indexes with Firestore, but it’s now separate from the security rules.

Every Firestore document is indexed by default. If you want to make compound or sorted queries, simply go to the Indexes tab next to the Rules tab in the console. From there, making the indexes is pretty self-explanatory.

Conclusion

I think that’s about it for Cloud Firestore’s security rules. At the very least, it should be enough so that you can navigate through the official docs for it on your own if you need to get into the finer details.

A couple of you from Reddit have asked me to write about this after I wrote Understanding Firebase Realtime Database Security Rules. Although I already had this post planned, I’m glad to have gotten input from you! Feel free to leave any suggestions in the comments if you want me to touch on a particular topic.