• Blog
  • Documentation
  • Courses
  • Changelog
  • AI Starters
  • UI Kit
  • FAQ
  • Supamode
    New
  • Pricing

Launch your next SaaS in record time with Makerkit, a React SaaS Boilerplate for Next.js and Supabase.

Makerkit is a product of Makerkit Pte Ltd (registered in the Republic of Singapore)Company Registration No: 202407149CFor support or inquiries, please contact us

About
  • FAQ
  • Contact
  • Verify your Discord
  • Consultation
  • Open Source
  • Become an Affiliate
Product
  • Documentation
  • Blog
  • Changelog
  • UI Blocks
  • Figma UI Kit
  • AI SaaS Starters
License
  • Activate License
  • Upgrade License
  • Invite Member
Legal
  • Terms of License

Using Firestore in Firebase Storage Rules

Sep 29, 2022

Firebase Storage now allows you to use Firestore queries to in your security rules. Here is all you need to know!

firestore
firebase

Finally, Firebase has shipped one of the most requested features by customers: using Firestore queries in the Firebase Storage security rules: this is incredibly useful when accessing data that is not part of the user's auth metadata: as it turns out, it's a very common scenario.

The Firebase team has historically warned that performance was the key reason that adding this feature was not feasible, and honestly I was sort of disillusioned this would be ever shipped. I am so glad I was wrong.

Firestore functions within the Storage Security Rules

The Storage Security rules have been enriched with new powerful functions that allow cross-service communication between Firebase Firestore and Firebase Storage.

We have access to two new functions:

  1. firestore.get: allows us to fetch the full object of a Firestore document
  2. firestore.exists: allows us to check if a document exists

This is useful in many situations, such as when a Storage asset is shared between many users that belong to the same group.

...a look at the past

If you have read my article about Firebase Storage group security, you'll remember that we used a valur stored in the user's custom claims to check that the user's group could read or write to Storage asset under a specific path.

For example, assuming the user belonged to the organization with ID 123, then the user could only read or write to the path organizations/123/**.

To do this, we used a small hack:

  1. Added organizationId to the asset's metadata
  2. Stored a custom claim organizationId in the user's authentication data
  3. Compared the two using the Firebase Storage rules

The biggest issues were:

  1. Propagating the custom claims to the client wen they changed
  2. Updating the custom claim when the user changed organization or created one

Long story short, it was a hassle. Thankfully, the new Firebase Storage rules will allow us to skip all of this.

The new way: How to use Firestore queries in Storage Security Rules

Let's assume that the users of an organizations have a shared Storage folder at /organizations/{organizationId}, and that the Firestore entity of the organization has the following information:

tsx
interface Organization {
members: {
[userId]: UserRole;
}
}

As you can see, we have access to a user ID using the path /organizations/ {organizationId} and by accessing the object members.{userId}.

When writing our Storage rules to protect the organization's assets at /organizations/{organizationId}/{fileName=**}, we can write the following:

js
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
function userId() {
return request.auth.uid;
}
function getOrganization(uid) {
return firestore.get(/databases/(default)/documents/organizations/$(uid));
}
function getOrganizationMembers(uid) {
return getOrganization(uid).data.members;
}
match /organizations/{organizationId}/{fileName=**} {
allow read, write: if userId() in getOrganizationMembers(organizationId);
}
}
}

Thanks to the above, we protect writes and reads to /organizations/ {organizationId}/{fileName=**} to the users whose ID is in the members's object of the organization's Firestore record. This waaay easier than the custom claims hack we had to resort to before this was available.

Enabling cross-service communication

This feature is already enabled in your local emulators if you're running the version 11.10.0 of the firebase-tools package, but you will need to enable cross-communication by updating the rules in your Firebase Console.

By enabling the Firestore and Storage services to communicate, you're effectively giving permissions to Firebase Storage to read your Firestore data.

For better performance ensure that both services are running within the same region which will result in the fastest round-trips between the services.

Some other posts you might like...
Dec 17, 2022How to reduce and boost your Firebase cold start timesFirebase cold start times are a common problem for developers. In this tutorial, we'll show you how to reduce and boost your Firebase cold start times.
Oct 21, 2022Counting a collection's documents with Firebase FirestoreIn this article, we learn how to count the number of documents in a Firestore collection using a custom React.js hook.
Oct 21, 2022Pagination with React.js and Firebase FirestoreIn this article, we learn how to paginate data fetched from Firebase Firestore with React.js
Oct 6, 2022Limiting the Firebase Storage space used by each customerLimiting the amount of Storage space used by your customers can be tricky. In this article, we show how to set a quota for each of your customers.
Oct 6, 2022Creating a Waitlist with Firebase AuthImplement a waitlist sign-up with Firebase Auth and allow sign-ins in batches to your SaaS