Restrict access to Firebase Storage files using security rules that check request.auth for authenticated users, validate file metadata like size and content type, and scope file paths to user IDs. Storage security rules are separate from Firestore rules and use their own syntax with match patterns on file paths. The most common pattern grants each user read/write access only to files under their own UID folder, preventing unauthorized access to other users' uploads.
Securing Firebase Storage Files with Security Rules
Firebase Storage uses security rules to control who can upload, download, and delete files. By default, new projects have rules that deny all access. This tutorial shows how to write rules that authenticate users, validate uploads, restrict access by user, and set up different access levels for public and private files. All rules are defined in storage.rules and deployed with the Firebase CLI.
Prerequisites
- A Firebase project with Storage enabled
- Firebase CLI installed (npm install -g firebase-tools)
- Firebase Authentication set up with at least one sign-in method
- Basic understanding of Firebase security rules syntax
Step-by-step guide
Understand the default Storage rules
Understand the default Storage rules
When you enable Firebase Storage, the default rules deny all read and write access. This is the most secure starting point. You must explicitly grant access in your rules. Storage rules use match patterns on file paths and allow/deny based on conditions. The request object contains auth information and the resource being accessed.
1rules_version = '2';2service firebase.storage {3 match /b/{bucket}/o {4 // Default: deny all access5 match /{allPaths=**} {6 allow read, write: if false;7 }8 }9}Expected result: All read and write operations are denied. Your app will show 'storage/unauthorized' errors until you add specific rules.
Allow authenticated users to read and write
Allow authenticated users to read and write
The most basic useful rule checks request.auth to ensure a user is signed in. This prevents anonymous access while allowing any authenticated user to read and write files. Use request.auth != null as the condition. You can further restrict by checking request.auth.uid to limit access to specific users.
1rules_version = '2';2service firebase.storage {3 match /b/{bucket}/o {4 // Only authenticated users can read or write5 match /{allPaths=**} {6 allow read, write: if request.auth != null;7 }8 }9}Expected result: Signed-in users can upload and download any file. Unauthenticated requests are rejected with a permission error.
Scope file access to individual users
Scope file access to individual users
The most common pattern creates a folder per user using their UID and restricts each user to their own folder. The match pattern captures the userId from the path, and the rule compares it to request.auth.uid. This ensures users can only access their own files. Structure your client-side upload paths as users/{uid}/filename to match this rule.
1rules_version = '2';2service firebase.storage {3 match /b/{bucket}/o {4 // Each user can only access their own folder5 match /users/{userId}/{allPaths=**} {6 allow read, write: if request.auth != null7 && request.auth.uid == userId;8 }910 // Public assets readable by anyone, writable by admins11 match /public/{allPaths=**} {12 allow read: if true;13 allow write: if request.auth != null14 && request.auth.token.admin == true;15 }16 }17}Expected result: Each user can only read and write files in their own users/{uid}/ folder. Public assets are readable by everyone.
Validate file size and content type on upload
Validate file size and content type on upload
Use request.resource to validate the file being uploaded. Check request.resource.size to enforce a maximum file size and request.resource.contentType to restrict allowed file types. These validations happen server-side and cannot be bypassed by the client. Combine size and type checks with authentication for comprehensive upload validation.
1rules_version = '2';2service firebase.storage {3 match /b/{bucket}/o {4 match /users/{userId}/avatar.{ext} {5 // Only the file owner can upload their avatar6 // Max 5MB, images only7 allow read: if request.auth != null;8 allow write: if request.auth != null9 && request.auth.uid == userId10 && request.resource.size < 5 * 1024 * 102411 && request.resource.contentType.matches('image/.*');12 }1314 match /users/{userId}/documents/{document} {15 // Max 10MB, PDFs and images only16 allow read: if request.auth != null17 && request.auth.uid == userId;18 allow write: if request.auth != null19 && request.auth.uid == userId20 && request.resource.size < 10 * 1024 * 102421 && (request.resource.contentType == 'application/pdf'22 || request.resource.contentType.matches('image/.*'));23 }24 }25}Expected result: Uploads exceeding the size limit or with disallowed content types are rejected. Valid uploads from the file owner succeed.
Deploy Storage rules with the Firebase CLI
Deploy Storage rules with the Firebase CLI
Save your rules in the storage.rules file in your project root. Then deploy them using the Firebase CLI. Rules take effect within a few seconds for new operations and up to 10 minutes for active connections. Always test rules in the Firebase Console's Rules Playground before deploying to production.
1# Deploy only storage rules2firebase deploy --only storage34# Or deploy everything5firebase deployExpected result: The CLI confirms the rules were deployed successfully. New operations immediately follow the updated rules.
Upload files with matching client-side paths
Upload files with matching client-side paths
Your client-side upload code must use paths that match your security rules. If your rules expect files under users/{userId}/, your upload code must construct paths using the authenticated user's UID. Use ref() to create a reference to the target path and uploadBytes() or uploadBytesResumable() to upload the file.
1import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage'2import { getAuth } from 'firebase/auth'34const storage = getStorage()5const auth = getAuth()67async function uploadAvatar(file: File) {8 const user = auth.currentUser9 if (!user) throw new Error('Must be signed in to upload.')1011 // Path must match the security rule pattern12 const avatarRef = ref(storage, `users/${user.uid}/avatar.jpg`)1314 try {15 const snapshot = await uploadBytes(avatarRef, file, {16 contentType: file.type17 })18 const downloadUrl = await getDownloadURL(snapshot.ref)19 console.log('Avatar uploaded:', downloadUrl)20 return downloadUrl21 } catch (error: any) {22 if (error.code === 'storage/unauthorized') {23 console.error('Upload rejected by security rules.')24 } else {25 console.error('Upload failed:', error.message)26 }27 throw error28 }29}Expected result: The avatar is uploaded to the user's folder and a download URL is returned. Unauthorized uploads are rejected with a clear error.
Complete working example
1rules_version = '2';2service firebase.storage {3 match /b/{bucket}/o {45 // User-scoped files: only the owner can read/write6 match /users/{userId}/{allPaths=**} {7 allow read: if request.auth != null8 && request.auth.uid == userId;9 allow write: if request.auth != null10 && request.auth.uid == userId11 && request.resource.size < 10 * 1024 * 1024;12 }1314 // User avatars: owner writes, all authenticated users read15 match /avatars/{userId}/avatar.{ext} {16 allow read: if request.auth != null;17 allow write: if request.auth != null18 && request.auth.uid == userId19 && request.resource.size < 5 * 1024 * 102420 && request.resource.contentType.matches('image/.*');21 }2223 // Public assets: anyone reads, only admins write24 match /public/{allPaths=**} {25 allow read: if true;26 allow write: if request.auth != null27 && request.auth.token.admin == true;28 }2930 // Shared project files: team members read/write31 match /projects/{projectId}/{allPaths=**} {32 allow read, write: if request.auth != null33 && request.auth.token.projectIds is list34 && projectId in request.auth.token.projectIds;35 }3637 // Deny everything else38 match /{allPaths=**} {39 allow read, write: if false;40 }41 }42}Common mistakes when restricting Access to Firebase Storage Files
Why it's a problem: Using Firestore security rules syntax in Storage rules — the two are different DSLs
How to avoid: Storage rules use request.resource.size and request.resource.contentType for uploads, not resource.data like Firestore. Storage rules match file paths, not document paths.
Why it's a problem: Uploading to a path that does not match any security rule pattern, causing silent rejections
How to avoid: Ensure your client-side upload path exactly matches the pattern in your rules. If your rule expects /users/{userId}/avatar.jpg, uploading to /user-files/{uid}/avatar.jpg will be denied.
Why it's a problem: Forgetting that request.resource is only available on write operations, causing rules to fail on reads
How to avoid: Only use request.resource (size, contentType) in write rules. For read rules, use resource (without request.) to access the existing file's metadata.
Best practices
- Always scope user files under a UID-based path like /users/{userId}/ to prevent cross-user access
- Validate both file size and content type in write rules to prevent abuse and storage cost overruns
- Use separate rule blocks for different access levels: private user files, shared team files, and public assets
- Test rules in the Firebase Console Rules Playground before deploying to production
- Set a maximum file size in rules as a server-side enforcement even if you validate client-side
- Use custom claims (request.auth.token.admin) for role-based access rather than hardcoding UIDs in rules
- Deploy rules with firebase deploy --only storage to update rules without affecting other services
- Configure CORS on your Storage bucket to prevent unauthorized cross-origin access to download URLs
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Firebase Storage bucket where users upload profile pictures and documents. Write comprehensive Firebase Storage security rules that: restrict each user to their own /users/{uid}/ folder, limit avatar uploads to 5MB images only, limit document uploads to 10MB PDFs and images, make profile pictures readable by all authenticated users, and deny everything else.
Generate Firebase Storage security rules for a multi-tenant application where users have private files under /users/{uid}/, team shared files under /teams/{teamId}/, and public assets under /public/. Include file size limits, content type validation, and role-based access using custom claims. Also show the client-side TypeScript upload code that matches these rule paths.
Frequently asked questions
Are Firebase Storage rules the same as Firestore rules?
No. They use a similar syntax but are separate systems with different objects. Storage rules use request.resource.size and request.resource.contentType for uploads, while Firestore rules use request.resource.data for document fields. They are defined in different files and deployed independently.
Can I restrict downloads to specific IP addresses?
No. Firebase Storage security rules cannot check IP addresses. For IP-based restrictions, use Cloud Storage IAM policies directly on the Google Cloud Console or put a Cloud Function proxy in front of Storage.
Do download URLs bypass security rules?
Yes. Download URLs generated by getDownloadURL() include a token that grants read access regardless of security rules. Anyone with the URL can access the file. To revoke access, regenerate the file's token in the Firebase Console or re-upload the file.
How do I make a file truly public?
Set allow read: if true in your Storage rules for the file's path. Alternatively, make the entire bucket public via Google Cloud Console IAM by granting allUsers the Storage Object Viewer role, but this bypasses all Firebase rules.
Can I use custom claims in Storage rules?
Yes. Access custom claims via request.auth.token in Storage rules. For example, request.auth.token.admin == true checks for an admin custom claim. Set custom claims using the Firebase Admin SDK server-side.
Can RapidDev help configure Firebase Storage security rules for my application?
Yes. RapidDev can design and implement Storage security rules tailored to your access patterns, including user-scoped files, team sharing, role-based access, and upload validation.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation