This tutorial aims to provide you with the necessary knowledge to write Firestore Security Rules. Security rules are essential in safeguarding your Firestore database by determining who has read and write access to your database.
By the end of this tutorial, you will:
Prerequisites:
Firestore Security Rules use a syntax that resembles JavaScript, with some differences. The rules are composed of service blocks that specify the service, match statements that specify document paths, and allow expressions that grant access.
Here is a basic example:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
In the code above, {document=**}
matches request to any document in the database, and allow read, write: if false;
denies all read and write operations.
One key concept to understand is that security rules are not filters. Firestore does not filter data on the server. Rather, it checks each query against its potential result set.
Rules are evaluated in the order they are defined, but only the first matching allow expression is evaluated.
This rule allows a user to read and write their own documents.
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
}
}
}
In the code above, request.auth.uid
represents the ID of the user making the request, and userId
is the ID of the user document being accessed.
This rule allows only users with the role 'admin' to write data.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
allow read: if true;
}
}
}
This rule retrieves the role field of the user document and checks if it's 'admin'.
We've covered how to write basic and more complex Firestore Security Rules. We've also looked at how rules are not filters and their evaluation order.
Next, try to write rules for your own Firestore database. Remember to always test your rules thoroughly before deploying.
email
field stays the same.published
field is true
.service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow update: if request.auth.uid == userId && request.resource.data.email == resource.data.email;
}
}
}
This rule checks if the email
field in the new data (request.resource.data.email
) is the same as the email
field in the existing document (resource.data.email
).
service cloud.firestore {
match /databases/{database}/documents {
match /articles/{articleId} {
allow read: if resource.data.published == true;
}
}
}
This rule allows reading an article document only if the published
field is true
. It doesn't check who the user is, so it applies to all users.
Keep practicing by writing rules for different scenarios and testing them out.