FirebaseError: Missing or insufficient permissions: The following request was denied by Firestore Security Rules:

This is the error I’m facing for the past 3 days now. can you please help. I am now trying to migrate to firestore since I’m now satisfied with my current build, but I keep encountering this error even after clicking “Fix Error” every time this shows.

FirebaseError: Missing or insufficient permissions: The following request was denied by Firestore Security Rules:
{
“auth”: {
“uid”: “tlaHSYI6w3NUx5UNTaEq5hMsoxv2”,
“token”: {
“name”: “leo brazal”,
“email”: “leo********@gmail.com”, (edited just in case)
“email_verified”: true,
“phone_number”: null,
“sub”: “tlaHSYI6w3NUx5UNTaEq5hMsoxv2”,
“firebase”: {
“identities”: {
google.com”: [
“114304064982832754946”
]
},
“sign_in_provider”: “google.com”,
“tenant”: null
}
}
},
“method”: “get”,
“path”: “/databases/(default)/documents/users/tlaHSYI6w3NUx5UNTaEq5hMsoxv2”
}
at handleAuthUser (https://6000-firebase-inventory-try-ol3-1761711466612.cluster-cz5nqyh5nreq6ua6gaqd7okl7o.cloudworkstations.dev/_next/static/chunks/src_b897ca5f._.js:2505:41)
at async AuthProvider.useEffect.unsubscribe [as next] (https://6000-firebase-inventory-try-ol3-1761711466612.cluster-cz5nqyh5nreq6ua6gaqd7okl7o.cloudworkstations.dev/_next/static/chunks/src_b897ca5f._.js:2529:33)

This is the steps that the error shows. this is the start of the sign up/ sign in flow.

after clicking Sign up with Google. and choosing account to sign up.

is the problem on my end? can someone please help? simple terms only so that I can understand please.

This error means the authenticated user does not have permission to read the document at:

/users/tlaHSYI6w3NUx5UNTaEq5hMsoxv2

Even though the user is logged in (auth is present), your Firestore Security Rules are blocking the read request.

The request is a get on a user document, but your rules likely don’t allow users to read that path, or they may require conditions you aren’t meeting.

If your rules don’t allow a user to read their own user doc, Firestore will throw Missing or insufficient permissions.

1 Like

that’s what the AI told me too. but it’s not making the correction properly even with countless auto fix.

Does your Firestore Security Rule look something like this:

match /databases/{database}/documents {
    match /users/{userId} {
      // Allow a user to read or update ONLY their own user document
      allow read, update: if request.auth != null && request.auth.uid == userId;
      
      // Allow creating a user doc only if they are authenticated
      allow create: if request.auth != null;
    }
  }


is this it?

Add this under your match /databases/{database}/documents block:

match /users/{userId} {
  // User can read or update ONLY their own profile
  allow read, update: if isOwner(userId);

  // Allow a signed-in user to create their own record
  allow create: if isSignedIn();

  // Admins can do anything
  allow read, write: if isAdmin();
}

Sebastian, I have another thread I just started but noticed you seem to understand this and I’m having similar issues. Let me know if you need to see certain parts of my code. This web app doesn’t really need to be super secure; it’s just internal use for my company of a few guys. That being said I dont see the need to use any of this real email authentication, I’d prefer to get back to how it was doing it somehow, the users are stored on the firestore database and it matches log in info to a user and signs them in.

”Any help would be greatly appreciated. I have a web app I have been using for a time clock system for my company. The other day the Gemini and I were adding some features, and it prompted me to connect to Firebase Authentication. This is my first web app so I just clicked that. The way my web app was working, my user logins are stored inside the firestore database. All clock in/out times, timesheet signatures, etc gets stored on there and it was working great. But ever since it added the authentication, I can’t login and says I’m missing permissions. I’ve been trying to fix it for weeks now and cannot figure it out. Any suggestions?? Thanks”

Still no luck with this one. Migration from local to cloud with Firestore authentication cannot be completed properly. Going on a loop for 4 days now with FirebaseError: Missing or insufficient permissions.

I’m not sure if you are dealing with a similar issue, but Gemini on mine had changed the project ID inside my firestore.rules file and it didn’t match my project ID of the real one inside the firebase console. I was getting that same insufficient permissions thing but once I corrected the project ID, that part went away. I still can’t login and am getting this code from a firestore security rule error. All my logins are stored inside my firestore database under “users” and I am stumped on why I can’t log in at this point too. I desperately need this web app back up and running. Anyhow maybe the project ID will help you!

{
“operation”: “get”,
“path”: “users/MGR001”,
“resource”: {
“employeeId”: “MGR001”
}
}

Could you post the whole rules file from the rules tab in the firestore section of the Firebase console? It should be at https://console.firebase.google.com/project/_/firestore/databases/_/rules

this is the current Rule in place. Thank you for taking your time on this.

/**

  • @fileoverview Firestore Security Rules for StorePilot.

  • Core Philosophy:

  • This ruleset enforces a strict ownership model, primarily based on path-based authorization.

  • Each data entity (Company, Store, ProductGroup, Item, UserProfile, SalesTransaction, Expense, Customer)

  • is secured within a hierarchical structure, ensuring that access is controlled at each level.

  • Authorization Independence is achieved through data denormalization (companyId, role) on the UserProfile

  • to avoid costly and complex get() calls in the rules.

  • Data Structure:

    • /users/{userId}: User profile information, owned exclusively by the user. Contains denormalized
  • ‘companyId’ and ‘role’ for authorization purposes.

    • /companies/{companyId}: Company information.
    • /companies/{companyId}/stores/{storeId}: Store information, nested under a company.
    • /companies/{companyId}/stores/{storeId}/productGroups/{productGroupId}: Product groups, nested under a store.
    • /companies/{companyId}/stores/{storeId}/productGroups/{productGroupId}/items/{itemId}: Items, nested under a product group.
    • /companies/{companyId}/stores/{storeId}/salesTransactions/{transactionId}: Sales transactions for a store.
    • /companies/{companyId}/stores/{storeId}/expenses/{expenseId}: Expenses for a store.
    • /companies/{companyId}/customers/{customerId}: Customers for a company.
    • /roles_admin/{userId}: Documents defining admin role via document existence.
  • Key Security Decisions:

    • Strict user-ownership model for /users/{userId} and its subcollections.
    • Denormalization of ‘companyId’ and ‘role’ on the UserProfile for efficient authorization checks.
    • Admin role defined via document existence in /roles_admin/{userId}.
    • No public listing of user profiles or other private data.
    • All write operations require authentication and proper authorization.
      */
      rules_version = ‘2’;
      service cloud.firestore {
      match /databases/{database}/documents {

    /**

    • @description Allows a user to manage their own profile.
    • @path /users/{userId}
    • @allow (create) User with ID ‘user123’ creates a profile with id: ‘user123’.
    • @deny (create) User with ID ‘user123’ attempts to create a profile with id: ‘user456’.
    • @allow (get, list, update, delete) User with ID ‘user123’ reads, updates, or deletes their own profile.
    • @deny (get, list, update, delete) User with ID ‘user123’ attempts to read, update, or delete the profile of user ‘user456’.
    • @principle Enforces document ownership for writes. Restricts access to a user’s own data tree.
      */
      match /users/{userId} {
      function isOwner(userId) {
      return request.auth != null && request.auth.uid == userId;
      }
      function isExistingOwner(userId) {
      return isOwner(userId) && exists(resource);
      }
      allow get: if isOwner(userId);
      allow list: if isOwner(userId);
      allow create: if isOwner(userId) && request.auth.uid == userId;
      allow update: if isExistingOwner(userId);
      allow delete: if isExistingOwner(userId);
      }

    /**

    • @description Allows anyone to read company information, but only admins can create, update, or delete.
    • @path /companies/{companyId}
    • @allow (get, list) Any user can read company data.
    • @allow (create) Admin creates a new company.
    • @deny (create) Non-admin attempts to create a company.
    • @allow (update, delete) Admin updates/deletes a company.
    • @deny (update, delete) Non-admin attempts to update/delete a company.
    • @principle Public read with owner-only writes + Admin role.
      */
      match /companies/{companyId} {
      allow get: if true;
      allow list: if true;
      allow create: if isAdmin();
      allow update: if isAdmin();
      allow delete: if isAdmin();
      }

    /**

    • @description Allows users within the same company to manage stores.
    • @path /companies/{companyId}/stores/{storeId}
    • @allow (get, list) Any authenticated user can read store data.
    • @allow (create) Admin or User with correct companyId can create a store.
    • @deny (create) User attempts to create a store with incorrect companyId.
    • @allow (update, delete) Admin or User with correct companyId can update/delete a store.
    • @deny (update, delete) User attempts to update/delete a store with incorrect companyId.
    • @principle Enforces company-level access control.
      */
      match /companies/{companyId}/stores/{storeId} {
      allow get: if isSignedIn();
      allow list: if isSignedIn();
      allow create: if isAdmin() || (isSignedIn() && request.resource.data.companyId == companyId);
      allow update: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      allow delete: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      }

    /**

    • @description Allows users within the same company to manage product groups.
    • @path /companies/{companyId}/stores/{storeId}/productGroups/{productGroupId}
    • @allow (get, list) Any authenticated user can read product group data.
    • @allow (create) Admin or User with correct companyId can create a product group.
    • @deny (create) User attempts to create a product group with incorrect companyId.
    • @allow (update, delete) Admin or User with correct companyId can update/delete a product group.
    • @deny (update, delete) User attempts to update/delete a product group with incorrect companyId.
    • @principle Enforces company-level access control.
      */
      match /companies/{companyId}/stores/{storeId}/productGroups/{productGroupId} {
      allow get: if isSignedIn();
      allow list: if isSignedIn();
      allow create: if isAdmin() || (isSignedIn() && request.resource.data.companyId == companyId);
      allow update: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      allow delete: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      }

    /**

    • @description Allows users within the same company to manage items.
    • @path /companies/{companyId}/stores/{storeId}/productGroups/{productGroupId}/items/{itemId}
    • @allow (get, list) Any authenticated user can read item data.
    • @allow (create) Admin or User with correct companyId can create an item.
    • @deny (create) User attempts to create an item with incorrect companyId.
    • @allow (update, delete) Admin or User with correct companyId can update/delete an item.
    • @deny (update, delete) User attempts to update/delete an item with incorrect companyId.
    • @principle Enforces company-level access control.
      */
      match /companies/{companyId}/stores/{storeId}/productGroups/{productGroupId}/items/{itemId} {
      allow get: if isSignedIn();
      allow list: if isSignedIn();
      allow create: if isAdmin() || (isSignedIn() && request.resource.data.companyId == companyId);
      allow update: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      allow delete: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      }

    /**

    • @description Allows users within the same company to manage sales transactions.
    • @path /companies/{companyId}/stores/{storeId}/salesTransactions/{transactionId}
    • @allow (get, list) Any authenticated user can read sales transaction data.
    • @allow (create) Admin or User with correct companyId can create a sales transaction.
    • @deny (create) User attempts to create a sales transaction with incorrect companyId.
    • @allow (update, delete) Admin or User with correct companyId can update/delete a sales transaction.
    • @deny (update, delete) User attempts to update/delete a sales transaction with incorrect companyId.
    • @principle Enforces company-level access control.
      */
      match /companies/{companyId}/stores/{storeId}/salesTransactions/{transactionId} {
      allow get: if isSignedIn();
      allow list: if isSignedIn();
      allow create: if isAdmin() || (isSignedIn() && request.resource.data.companyId == companyId);
      allow update: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      allow delete: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      }

    /**

    • @description Allows users within the same company to manage expenses.
    • @path /companies/{companyId}/stores/{storeId}/expenses/{expenseId}
    • @allow (get, list) Any authenticated user can read expense data.
    • @allow (create) Admin or User with correct companyId can create an expense.
    • @deny (create) User attempts to create an expense with incorrect companyId.
    • @allow (update, delete) Admin or User with correct companyId can update/delete an expense.
    • @deny (update, delete) User attempts to update/delete an expense with incorrect companyId.
    • @principle Enforces company-level access control.
      */
      match /companies/{companyId}/stores/{storeId}/expenses/{expenseId} {
      allow get: if isSignedIn();
      allow list: if isSignedIn();
      allow create: if isAdmin() || (isSignedIn() && request.resource.data.companyId == companyId);
      allow update: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      allow delete: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      }

    /**

    • @description Allows users within the same company to manage customers.
    • @path /companies/{companyId}/customers/{customerId}
    • @allow (get, list) Any authenticated user can read customer data.
    • @allow (create) Admin or User with correct companyId can create a customer.
    • @deny (create) User attempts to create a customer with incorrect companyId.
    • @allow (update, delete) Admin or User with correct companyId can update/delete a customer.
    • @deny (update, delete) User attempts to update/delete a customer with incorrect companyId.
    • @principle Enforces company-level access control.
      */
      match /companies/{companyId}/customers/{customerId} {
      allow get: if isSignedIn();
      allow list: if isSignedIn();
      allow create: if isAdmin() || (isSignedIn() && request.resource.data.companyId == companyId);
      allow update: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      allow delete: if isAdmin() || (isSignedIn() && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.companyId == companyId);
      }

    /**

    • @description Defines admin role via document existence.
    • @path /roles_admin/{userId}
    • @allow (get) Any authenticated user can check if an admin exist.
    • @allow (list) Any authenticated user can list the admins.
    • @allow (create) Only the first user can create the admin.
    • @deny (create) Non-admin attempts to create a roles_admin.
    • @allow (update, delete) Admin can update/delete a roles_admin.
    • @deny (update, delete) Non-admin attempts to update/delete a roles_admin.
    • @principle Public read with owner-only writes + Admin role.
      */
      match /roles_admin/{userId} {
      allow get: if isSignedIn();
      allow list: if false; // Listing admins is disabled for security
      allow create: if !exists(/databases/$(database)/documents/roles_admin/{userId}) && isAdmin();
      allow update: if isAdmin();
      allow delete: if isAdmin();
      }

    function isSignedIn() {
    return request.auth != null;
    }

    function isAdmin() {
    return request.auth != null && exists(/databases/$(database)/documents/roles_admin/$(request.auth.uid));
    }
    }
    }

Hmmm, those rules look good to me, and when I run the simulated request from your first error they seem to allow the request. In the second request you posted the authentication is null, indicating the user isn’t logged in. Are you getting this error within Firebase Studio, or from the deployed app? If it’s within Firebase studio, I’ve seen problems before with the authentication not re-triggering after a change and restarting the dev server fixed it.

We’ve encountered similar challenges, and while things work once fixed, the process of resolving issues takes too much time and effort. For us, it’s more efficient to use deep-agent products that get the job done quickly. Instead of spending time developing Firebase-based products, we use that time to build our own intended products. Although we’d love to handle all projects with Google and Firebase, it’s simply too time-consuming when deep-agent solutions can achieve the same results. We still plan to use Firebase but are prioritizing new products and projects on deep-agent platforms. If Firebase becomes more stable and powerful in the future, we’ll gladly return because we like Google. However, some products work flawlessly, while others have inherent roadblocks that limit their usability. Even Google’s own tools, such as Analytics, are easier to implement within deep-agent systems than in Firebase. Deep-agent platforms feel like driving a car with automatic transmission and partial self-driving—smooth and intuitive—even with Google’s integrations like Analytics. When this is the case for many products, it’s better to let others spend the time fixing issues while we focus on building products instead of constantly troubleshooting Firebase. Unfortunately, we don’t have that luxury, but we respect the hard work being done to make Firebase function—it’s impressive, great job.

This happened to me and took me multiple days to figure out. But I think what is happening to you is that the the program is trying to authorize you BEFORE authenticating you–when a new user signs up (which of course will fail). My solution was to specifically tell the AI prompt to make sure the new user is authenticated first and then proceed to the authorization process (access database). Hope this helps. E

Hey @leo_brazal :waving_hand:

That “Missing or insufficient permissions” error usually means your Firestore security rules are rejecting the request — even though the user is authenticated. It often happens when your rules don’t allow reads/writes for that user’s UID path, or when the Firestore document structure doesn’t match what the rules expect.

From your example, it looks like the app is trying to read from /users/tlaHSYI6w3NUx5UNTaEq5hMsoxv2, so you’ll want to double-check that your rules include something like:

match /users/{userId} {
  allow read, write: if request.auth != null && request.auth.uid == userId;
}

That should allow signed-in users to read and write only their own data securely.

Have you been able to fix it yet? If not, I specialize in Firestore rules, Firebase Auth integrations, and debugging complex permission setups — I can help you get everything working correctly without compromising security.

You can reach me here or starblackmedia@gmail.com if you’d like me to take a quick look at your setup.

— Sunny :rocket:
Firebase Studio & Full-Stack Developer

I have encountered the same problem and i have moved all the permission via secure back-end API and I am managing all access controls through code