Firebase Security Rules allow you to control who has access to your database, making them a critical part of your app's security. But like any other code, they can have bugs that may lead to serious security vulnerabilities. So, testing Firebase Security Rules is a must.
To test the rules, we use the Firebase Emulator Suite, a set of tools that allows you to run Firebase services locally, and Firebase's security rules testing library.
First, install the Firebase CLI and initialize your project if you haven't already:
npm install -g firebase-tools
firebase init
Then, install the @firebase/rules-unit-testing library:
npm install --save-dev @firebase/rules-unit-testing
Now, let's write some tests. Here's a basic example:
const {initializeTestApp, assertFails} = require('@firebase/rules-unit-testing');
describe("Firebase Security Rules", () => {
it("deny read/write access to unauthorized users", async () => {
const db = initializeTestApp({projectId: 'my-project-id'}).firestore();
await assertFails(db.collection('users').doc('alice').get());
});
});
This test will fail if an unauthorized user can read Alice's document, which is what we want.
Here's a more complex example where we test that only admins can write to the 'admin' collection:
const {initializeTestApp, assertFails, assertSucceeds} = require('@firebase/rules-unit-testing');
describe("Firebase Security Rules", () => {
let db;
beforeEach(async () => {
// Set up mock user
db = initializeTestApp({
projectId: 'my-project-id',
auth: {uid: 'alice', admin: true}
}).firestore();
});
it("allow admins to write to 'admin' collection", async () => {
await assertSucceeds(db.collection('admin').doc('doc').set({foo: 'bar'}));
});
it("deny non-admins from writing to 'admin' collection", async () => {
// Change user to non-admin
db = initializeTestApp({
projectId: 'my-project-id',
auth: {uid: 'bob', admin: false}
}).firestore();
await assertFails(db.collection('admin').doc('doc').set({foo: 'bar'}));
});
});
In this tutorial, we learned why testing Firebase Security Rules is important and how to do it using the Firebase Emulator Suite and the @firebase/rules-unit-testing library. Now, you should be able to write your own tests and make your Firebase database more secure.
Solution:
it("allow authenticated users to read 'users' collection", async () => {
await assertSucceeds(db.collection('users').get());
});
Solution:
it("allow users to write to their own document", async () => {
await assertSucceeds(db.collection('users').doc('alice').set({foo: 'bar'}));
});
it("deny users from writing to other's document", async () => {
await assertFails(db.collection('users').doc('bob').set({foo: 'bar'}));
});
Keep practicing and try to come up with your own rules and tests for them. Happy coding!