Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Fix the Firebase Storage Unauthorized Error

The Firebase Storage 'unauthorized' error (storage/unauthorized) occurs when your security rules block the requested operation. The most common causes are default deny-all rules, the user not being authenticated when rules require auth, incorrect path patterns in rules, and CORS not being configured on the storage bucket. Fix it by updating your storage.rules to grant the appropriate permissions, ensuring the user is signed in before calling Storage APIs, and configuring CORS for browser-based access.

What you'll learn

  • How to diagnose the root cause of Firebase Storage unauthorized errors
  • How to write storage security rules that grant upload, download, and delete permissions
  • How to ensure the user is authenticated before making storage requests
  • How to configure CORS on your storage bucket to fix browser-based access errors
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate7 min read10-15 minFirebase JS SDK v9+, Cloud Storage for Firebase (all plans)March 2026RapidDev Engineering Team
TL;DR

The Firebase Storage 'unauthorized' error (storage/unauthorized) occurs when your security rules block the requested operation. The most common causes are default deny-all rules, the user not being authenticated when rules require auth, incorrect path patterns in rules, and CORS not being configured on the storage bucket. Fix it by updating your storage.rules to grant the appropriate permissions, ensuring the user is signed in before calling Storage APIs, and configuring CORS for browser-based access.

Fixing the Firebase Storage Unauthorized Error

When Firebase Storage returns a storage/unauthorized error, it means the security rules rejected the request. This tutorial walks through every common cause: default deny-all rules, auth state timing issues, path mismatches in rules, missing CORS configuration, and file size or content type restrictions. Each cause has a specific diagnostic step and fix.

Prerequisites

  • A Firebase project with Cloud Storage enabled
  • Firebase JS SDK v9+ installed
  • Access to the Firebase Console to edit storage rules
  • A storage operation (upload, download, or delete) that is returning the unauthorized error

Step-by-step guide

1

Check your current storage security rules

Open the Firebase Console, go to Storage > Rules. The default production rules deny all access: allow read, write: if false. If you have not updated these rules, every storage operation will return unauthorized. For development, you can temporarily allow all authenticated users to read and write. For production, write specific rules that match your access patterns.

typescript
1// Default rules (deny all) — this causes the unauthorized error
2rules_version = '2';
3service firebase.storage {
4 match /b/{bucket}/o {
5 match /{allPaths=**} {
6 allow read, write: if false;
7 }
8 }
9}
10
11// Fix: allow authenticated users to read/write their own files
12rules_version = '2';
13service firebase.storage {
14 match /b/{bucket}/o {
15 match /users/{userId}/{allPaths=**} {
16 allow read: if request.auth != null;
17 allow write: if request.auth != null
18 && request.auth.uid == userId
19 && request.resource.size < 10 * 1024 * 1024;
20 }
21 }
22}

Expected result: Your storage rules allow authenticated users to access files under their user-specific path.

2

Verify the user is authenticated before making storage calls

Storage security rules that check request.auth will reject requests from unauthenticated users. A common mistake is calling storage APIs before onAuthStateChanged fires — the user appears null even if they have a valid session. Always wait for the auth state to be determined before making storage requests.

typescript
1import { getAuth, onAuthStateChanged } from 'firebase/auth';
2import { getStorage, ref, uploadBytes } from 'firebase/storage';
3
4const auth = getAuth();
5const storage = getStorage();
6
7// WRONG: May run before auth is restored
8async function uploadNow(file: File) {
9 const storageRef = ref(storage, `uploads/${file.name}`);
10 await uploadBytes(storageRef, file); // Unauthorized!
11}
12
13// CORRECT: Wait for auth state first
14onAuthStateChanged(auth, async (user) => {
15 if (user) {
16 // Now it's safe to use storage
17 const storageRef = ref(storage, `users/${user.uid}/${file.name}`);
18 await uploadBytes(storageRef, file);
19 }
20});

Expected result: Storage operations are only attempted after Firebase Auth confirms the user is signed in, preventing unauthorized errors from timing issues.

3

Match the storage path in your code to the path in your rules

Storage rules use path patterns to match requests. If your code uploads to users/abc123/avatar.jpg but your rules only match uploads/{fileName}, the request will be denied. Check that the path in your ref() call matches a rule pattern that grants access. Use the Firebase Console Rules Playground to test specific paths and auth states.

typescript
1// Rules match /users/{userId}/{allPaths=**}
2// So your code MUST use paths under /users/{uid}/
3
4// WRONG: uploading to a path not covered by rules
5const wrongRef = ref(storage, `avatars/${user.uid}/photo.jpg`);
6
7// CORRECT: uploading to the user-scoped path that rules cover
8const correctRef = ref(storage, `users/${user.uid}/photo.jpg`);

Expected result: The storage path in your code matches the rule pattern, and the request is authorized.

4

Add validation rules for file size and content type

Storage rules can enforce file size limits and content type restrictions. If your rules include request.resource.size or request.resource.contentType checks, uploads that violate these constraints return the unauthorized error. Review your rules for these conditions and ensure uploaded files comply.

typescript
1rules_version = '2';
2service firebase.storage {
3 match /b/{bucket}/o {
4 match /users/{userId}/images/{fileName} {
5 allow read: if request.auth != null;
6 allow write: if request.auth != null
7 && request.auth.uid == userId
8 // File must be under 5 MB
9 && request.resource.size < 5 * 1024 * 1024
10 // File must be an image
11 && request.resource.contentType.matches('image/.*');
12 }
13 }
14}

Expected result: Only files that meet the size and content type constraints are accepted. Other files receive a clear unauthorized error.

5

Configure CORS for browser-based storage access

If you see a CORS error alongside or instead of the unauthorized error, the issue is that your storage bucket does not have CORS configured for your domain. Firebase Storage buckets have no CORS policy by default. Create a cors.json file and apply it using the gsutil CLI tool. Include your production domain and localhost for development.

typescript
1// cors.json
2[
3 {
4 "origin": [
5 "https://yoursite.com",
6 "http://localhost:3000",
7 "http://localhost:5173"
8 ],
9 "method": ["GET", "POST", "PUT", "DELETE"],
10 "maxAgeSeconds": 3600,
11 "responseHeader": ["Content-Type", "Authorization"]
12 }
13]
14
15// Apply with gsutil:
16// gsutil cors set cors.json gs://YOUR-PROJECT.appspot.com

Expected result: Browser requests to Firebase Storage include the correct CORS headers, and cross-origin uploads and downloads work without errors.

Complete working example

storage-with-auth.ts
1import { initializeApp } from 'firebase/app';
2import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
3import {
4 getStorage,
5 ref,
6 uploadBytes,
7 getDownloadURL,
8 deleteObject
9} from 'firebase/storage';
10import { FirebaseError } from 'firebase/app';
11
12const app = initializeApp({
13 // Your Firebase config
14});
15const auth = getAuth(app);
16const storage = getStorage(app);
17
18// Wait for auth before storage operations
19function getCurrentUser(): Promise<User> {
20 return new Promise((resolve, reject) => {
21 const unsubscribe = onAuthStateChanged(auth, (user) => {
22 unsubscribe();
23 if (user) resolve(user);
24 else reject(new Error('Not authenticated'));
25 });
26 });
27}
28
29// Safe upload with auth check
30export async function uploadFile(file: File, path: string): Promise<string> {
31 const user = await getCurrentUser();
32 const filePath = `users/${user.uid}/${path}`;
33 const fileRef = ref(storage, filePath);
34
35 try {
36 await uploadBytes(fileRef, file);
37 return getDownloadURL(fileRef);
38 } catch (error) {
39 if (error instanceof FirebaseError) {
40 if (error.code === 'storage/unauthorized') {
41 throw new Error(
42 'Upload denied. Check storage rules and auth state.'
43 );
44 }
45 }
46 throw error;
47 }
48}
49
50// Safe delete with error handling
51export async function deleteFile(path: string): Promise<void> {
52 const user = await getCurrentUser();
53 const filePath = `users/${user.uid}/${path}`;
54
55 try {
56 await deleteObject(ref(storage, filePath));
57 } catch (error) {
58 if (error instanceof FirebaseError) {
59 if (error.code === 'storage/object-not-found') return;
60 if (error.code === 'storage/unauthorized') {
61 throw new Error('Delete denied. Check storage rules.');
62 }
63 }
64 throw error;
65 }
66}

Common mistakes when fixing the Firebase Storage Unauthorized Error

Why it's a problem: Leaving the default deny-all storage rules in production

How to avoid: Update storage.rules to grant access based on authentication and path matching. Never use allow read, write: if true in production — always check request.auth.

Why it's a problem: Making storage calls before onAuthStateChanged confirms the user is signed in

How to avoid: Wait for onAuthStateChanged to fire with a non-null user before calling any Storage API. The auth token is attached to storage requests automatically but only after auth initialization completes.

Why it's a problem: Using a storage path in code that does not match any rule pattern

How to avoid: Check that your ref() paths match the match patterns in your storage rules. Use the Rules Playground in the Console to test specific paths with simulated auth states.

Why it's a problem: Not configuring CORS on the storage bucket for browser access

How to avoid: Create a cors.json file with your domains and apply it with gsutil cors set cors.json gs://YOUR-BUCKET. Include localhost origins for development.

Best practices

  • Always check request.auth in storage rules rather than using open rules
  • Scope file paths to user IDs (users/{uid}/...) to simplify rule writing
  • Validate file size and content type in both security rules and client-side code
  • Wait for auth initialization before making storage requests
  • Use the Rules Playground to test rule changes before publishing
  • Configure CORS for all domains that will access storage from the browser
  • Provide clear user-facing error messages for storage authorization failures

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Help me fix the Firebase Storage 'unauthorized' error. Show me how to write storage security rules that allow authenticated users to upload, download, and delete files under their user path. Include file size and content type validation, the CORS configuration needed for browser access, and how to ensure the user is authenticated before calling Storage APIs.

Firebase Prompt

Debug and fix Firebase Storage unauthorized errors. Create storage security rules for user-scoped file access with size and content type validation. Write a TypeScript utility that waits for auth before storage operations, handles the unauthorized error with clear messages, and includes a CORS configuration for the storage bucket.

Frequently asked questions

What does the storage/unauthorized error code mean?

It means your Firebase Storage security rules denied the requested operation (upload, download, or delete). Check your rules to ensure they grant permission for the specific path, auth state, and operation type.

Why do I get unauthorized even though my rules allow authenticated users?

Most likely your code runs the storage operation before Firebase Auth finishes restoring the session. Use onAuthStateChanged to wait for auth initialization before calling any storage API.

How do I allow public read access to all files?

Set allow read: if true in your storage rules for the paths you want to be public. Be careful — this makes every file in that path accessible to anyone with the URL.

Can I test storage rules locally with the Emulator?

Yes. The Firebase Storage Emulator runs on port 9199 and enforces your security rules. Use connectStorageEmulator(storage, '127.0.0.1', 9199) to connect your app to the local emulator.

Is the CORS error the same as the unauthorized error?

No. CORS errors come from missing CORS configuration on your storage bucket and appear as browser network errors. Unauthorized errors come from security rules rejecting the operation. You may see both if CORS is missing and rules are also blocking.

Can RapidDev help configure Firebase Storage security for a production application?

Yes, RapidDev can design and implement storage security rules, configure CORS, set up user-scoped file paths, and build upload/download flows with proper error handling for your specific use case.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.