Firebase Storage Security Rules
Storage Security Rules control who can upload, download, update metadata, and delete files in your Cloud Storage bucket. Without proper rules, files are either completely open to the public or completely inaccessible. Rules let you grant precise access based on who the user is, what file they are accessing, and what they are trying to do.
Rules Structure
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if false; // deny everything by default
}
}
}
The {bucket} variable matches your storage bucket name. The {allPaths=**} wildcard matches all file paths recursively. You replace these broad rules with specific path-based rules.
Key Variables in Storage Rules
request.auth— the authenticated user (nullif not logged in)request.auth.uid— the user's unique IDresource.size— size of the existing file in bytesrequest.resource.size— size of the incoming file in bytesresource.contentType— MIME type of the existing filerequest.resource.contentType— MIME type of the incoming file
Allowing Only Authenticated Users
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
Users Can Only Access Their Own Files
Use the user's UID in the file path and match it in the rule:
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /profile-photos/{userId}/{fileName} {
// Anyone logged in can read profile photos
allow read: if request.auth != null;
// Only the owner can upload or delete their own photo
allow write: if request.auth.uid == userId;
}
}
}
Restricting File Types
Allow uploads only for specific file types by checking the content type:
match /images/{userId}/{fileName} {
allow write: if request.auth.uid == userId
&& request.resource.contentType.matches("image/.*");
}
match /documents/{userId}/{fileName} {
allow write: if request.auth.uid == userId
&& (request.resource.contentType == "application/pdf"
|| request.resource.contentType == "text/plain");
}
Restricting File Size
Prevent large uploads that would eat your bandwidth quota:
match /uploads/{userId}/{fileName} {
allow write: if request.auth.uid == userId
// Limit to 5 MB
&& request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches("image/.*");
}
Public Read, Authenticated Write
This pattern works well for app assets that everyone can view but only admins can upload:
match /public/{fileName} {
allow read: if true;
allow write: if request.auth.token.admin == true;
}
Combining Multiple Conditions
rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
// Profile photos: anyone logged in can read, owner can write up to 2MB images
match /profile-photos/{userId}/{fileName} {
allow read: if request.auth != null;
allow write: if request.auth.uid == userId
&& request.resource.size < 2 * 1024 * 1024
&& request.resource.contentType.matches("image/.*");
allow delete: if request.auth.uid == userId;
}
// Post attachments: public read, author write
match /posts/{postId}/{fileName} {
allow read: if true;
allow write: if request.auth != null
&& request.resource.size < 10 * 1024 * 1024;
allow delete: if request.auth != null;
}
}
}
Testing Rules in the Console
The Firebase Console has a Rules Playground under Storage > Rules. Simulate requests by entering a file path, selecting an operation (read or write), providing a UID, and specifying file size and content type. The playground shows ALLOW or DENY along with which rule caused the decision.
Key Takeaway
Storage rules match file paths and check conditions against the requesting user and incoming file properties. Always restrict writes to authenticated users and use the user's UID in file paths to enforce per-user access. Add content type and file size checks to prevent abuse. Test your rules in the Rules Playground before deploying to production.
