Firestore
Permission Denied
Insufficient Permissions
Database Security
Firebase Errors

firestore PERMISSION_DENIED Missing or insufficient permissions

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

PERMISSION_DENIED: Missing or insufficient permissions in Firestore means the request reached Firestore, but the request did not satisfy the active security rules. The fix is usually not in the query syntax itself. It is in one of three areas: the user is not authenticated as expected, the document path does not match the rule, or the rule conditions do not allow the requested read or write.

Start With The Security Rules

Firestore reads and writes are checked against rules that look roughly like this:

text
1rules_version = '2';
2service cloud.firestore {
3  match /databases/{database}/documents {
4    match /users/{userId} {
5      allow read, write: if request.auth != null && request.auth.uid == userId;
6    }
7  }
8}

This rule says a signed-in user can access only their own document under /users/{userId}.

If your app tries to read /users/abc while the signed-in user's UID is xyz, Firestore rejects the request with the permission error.

Verify Authentication State

Many permission problems are actually auth-state problems. Check whether the client really has a signed-in user before making the request:

javascript
1import { getAuth } from "firebase/auth";
2
3const auth = getAuth();
4console.log(auth.currentUser?.uid);

If currentUser is null, rules that require request.auth != null will fail every time.

Also remember that auth initialization can be asynchronous. If you query Firestore before the auth state has settled, the request may run as an unauthenticated user.

Match The Query To The Rule Shape

Rules are evaluated against the actual document path and the data involved in the request. For example, this client read:

javascript
1import { doc, getDoc } from "firebase/firestore";
2
3const ref = doc(db, "users", auth.currentUser.uid);
4const snapshot = await getDoc(ref);

matches the earlier rule because the document path includes the user's own UID.

But this:

javascript
const ref = doc(db, "users", "someone-else");
const snapshot = await getDoc(ref);

fails for the same signed-in user because the rule condition no longer matches.

The same logic applies to collection queries. If your rules permit only documents owned by the current user, your query must be compatible with that rule design.

Writing Rules For Ownership

A common write rule checks the owner field in the incoming document:

text
1match /posts/{postId} {
2  allow create: if request.auth != null
3                && request.resource.data.ownerId == request.auth.uid;
4
5  allow update, delete: if request.auth != null
6                        && resource.data.ownerId == request.auth.uid;
7}

The distinction matters:

  • 'request.resource.data is the new incoming data.'
  • 'resource.data is the existing stored document.'

Using the wrong one is a frequent source of permission failures.

Use The Emulator Or Rules Playground

When the rule looks correct but requests still fail, test the scenario with Firestore's emulator or rules simulator. Those tools help answer:

  • Was the request authenticated?
  • Which path did Firestore evaluate?
  • Which rule branch denied the request?

Without that feedback, it is easy to keep changing client code when the real problem is the rule condition.

Admin SDK Is Different

Another important detail is that Firebase Admin SDK calls usually bypass Firestore security rules and use IAM instead. If a read works on your server but fails in the browser or mobile app, that is expected. The client SDK is evaluated against Firestore rules, while trusted backend code is not.

This difference often explains why "the same query works in one place but not another."

Common Pitfalls

The biggest mistake is blaming Firestore before checking whether the client is actually signed in. If request.auth is null, any auth-based rule denies access immediately.

Another common issue is mismatched paths. A rule for /users/{userId} does not automatically cover /profiles/{userId} or a subcollection unless you wrote rules for those paths too.

Developers also often confuse resource.data and request.resource.data, especially in create versus update rules. That leads to conditions that can never be true.

Finally, avoid loosening rules just to make the error disappear. If you change the rule to allow read, write: if true;, the error goes away, but so does your security model.

Summary

  • Firestore permission errors usually come from auth state, path mismatches, or failing rule conditions.
  • Check the signed-in user before you debug the query.
  • Make sure the document path and rule pattern actually match.
  • Use request.resource.data for incoming writes and resource.data for existing documents.
  • Test with the emulator or rules simulator instead of guessing why a rule failed.

Course illustration
Course illustration

All Rights Reserved.