# How to Fix the Firebase Storage Unauthorized Error

- Tool: Firebase
- Difficulty: Intermediate
- Time required: 10-15 min
- Compatibility: Firebase JS SDK v9+, Cloud Storage for Firebase (all plans)
- Last updated: March 2026

## 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.

## Before you start

- 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.

```
// Default rules (deny all) — this causes the unauthorized error
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

// Fix: allow authenticated users to read/write their own files
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/{allPaths=**} {
      allow read: if request.auth != null;
      allow write: if request.auth != null
        && request.auth.uid == userId
        && request.resource.size < 10 * 1024 * 1024;
    }
  }
}
```

**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.

```
import { getAuth, onAuthStateChanged } from 'firebase/auth';
import { getStorage, ref, uploadBytes } from 'firebase/storage';

const auth = getAuth();
const storage = getStorage();

// WRONG: May run before auth is restored
async function uploadNow(file: File) {
  const storageRef = ref(storage, `uploads/${file.name}`);
  await uploadBytes(storageRef, file); // Unauthorized!
}

// CORRECT: Wait for auth state first
onAuthStateChanged(auth, async (user) => {
  if (user) {
    // Now it's safe to use storage
    const storageRef = ref(storage, `users/${user.uid}/${file.name}`);
    await uploadBytes(storageRef, file);
  }
});
```

**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.

```
// Rules match /users/{userId}/{allPaths=**}
// So your code MUST use paths under /users/{uid}/

// WRONG: uploading to a path not covered by rules
const wrongRef = ref(storage, `avatars/${user.uid}/photo.jpg`);

// CORRECT: uploading to the user-scoped path that rules cover
const 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.

```
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/images/{fileName} {
      allow read: if request.auth != null;
      allow write: if request.auth != null
        && request.auth.uid == userId
        // File must be under 5 MB
        && request.resource.size < 5 * 1024 * 1024
        // File must be an image
        && request.resource.contentType.matches('image/.*');
    }
  }
}
```

**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.

```
// cors.json
[
  {
    "origin": [
      "https://yoursite.com",
      "http://localhost:3000",
      "http://localhost:5173"
    ],
    "method": ["GET", "POST", "PUT", "DELETE"],
    "maxAgeSeconds": 3600,
    "responseHeader": ["Content-Type", "Authorization"]
  }
]

// Apply with gsutil:
// 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 code example

File: `storage-with-auth.ts`

```typescript
import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged, User } from 'firebase/auth';
import {
  getStorage,
  ref,
  uploadBytes,
  getDownloadURL,
  deleteObject
} from 'firebase/storage';
import { FirebaseError } from 'firebase/app';

const app = initializeApp({
  // Your Firebase config
});
const auth = getAuth(app);
const storage = getStorage(app);

// Wait for auth before storage operations
function getCurrentUser(): Promise<User> {
  return new Promise((resolve, reject) => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      unsubscribe();
      if (user) resolve(user);
      else reject(new Error('Not authenticated'));
    });
  });
}

// Safe upload with auth check
export async function uploadFile(file: File, path: string): Promise<string> {
  const user = await getCurrentUser();
  const filePath = `users/${user.uid}/${path}`;
  const fileRef = ref(storage, filePath);

  try {
    await uploadBytes(fileRef, file);
    return getDownloadURL(fileRef);
  } catch (error) {
    if (error instanceof FirebaseError) {
      if (error.code === 'storage/unauthorized') {
        throw new Error(
          'Upload denied. Check storage rules and auth state.'
        );
      }
    }
    throw error;
  }
}

// Safe delete with error handling
export async function deleteFile(path: string): Promise<void> {
  const user = await getCurrentUser();
  const filePath = `users/${user.uid}/${path}`;

  try {
    await deleteObject(ref(storage, filePath));
  } catch (error) {
    if (error instanceof FirebaseError) {
      if (error.code === 'storage/object-not-found') return;
      if (error.code === 'storage/unauthorized') {
        throw new Error('Delete denied. Check storage rules.');
      }
    }
    throw error;
  }
}
```

## Common mistakes

- **Leaving the default deny-all storage rules in production** — undefined Fix: 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.
- **Making storage calls before onAuthStateChanged confirms the user is signed in** — undefined Fix: 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.
- **Using a storage path in code that does not match any rule pattern** — undefined Fix: 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.
- **Not configuring CORS on the storage bucket for browser access** — undefined Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/firebase-tutorial/how-to-fix-firebase-storage-unauthorized-error
© RapidDev — https://www.rapidevelopers.com/firebase-tutorial/how-to-fix-firebase-storage-unauthorized-error
