code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null - flutter

I am not able to read/write data to firestore with rules in place.
I can access my data and do operations on it with no rules set as shown below:
match /{document=**} {
allow read, write: if true;
}
But I am getting the "permission denied" error with following rules.
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
Here is my dart code:
if (uid == null) {
user = await a.currentUser();
uid = user.uid;
}
DocumentReference docRef = firestore.collection('users').document(uid);
CollectionReference locations = docRef.collection('locations');
await locations.document().setData(<String, double>{
'latitude': latitude,
'longitude': longitude,
});
I can think of two scenarios in which this request fails:
request.auth.uid == null. But I have a user logged in with firebase auth before this query.
My security rules and query doesn't match.
Please help me debug this issue.
Edit 1:
I have user authenticated during my firebase query as I changed the code to enter only if the user is authenticated as below:
User u = await a.onAuthStateChanged.first;
if (u != null) {....}
I was able to read/write with authentication using firebase simulator.
Is there anyway I can print the actual request being sent to the firebase from dart using cloud_firestore package?
Edit 2
Firestore.instance is working with rules
Firebaseapp configured to my specific app using configure,options isn't working.
Any help on why this might be happening?

Just change your rules to as below if you want to allow anybody to upload the documents.
allow read, write;
If you want to allow only authenticated users to allow upload the files or documents to your firebase change your rules to
allow read, write: if request.auth != null;

change your rules to allow read,write: if request.auth !=null;

Related

Permissions Problems with Flutter and FireBase FireStore

Can someone please help me I am a complete noob to FireStore and FireBase and am trying to do something simple and FireBase is saying I do not have permission to do it? I am using Flutter. I have the following rules set up in FireBase rules console. I only have one project and one firestore database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow write: if request.auth != null;
allow read: if true;
}
}
}
I have a collection of users setup which has a uid as the collection parameter and running the following code after signing into flutter anonymously which does not throw an error. UserID is set to a valid value.
void createUser(String userID, String userName, String password) async {
final CollectionReference _users =
FirebaseFirestore.instance.collection("Users");
final data = {"Created": DateTime.now(), "LastLoggedIn": DateTime.now()};
_users.doc(userID).set(data, SetOptions(merge: true));
}
I am getting the following error message
10.3.0 - [FirebaseFirestore][I-FST000001] Write at Users/QUIEvBpJeAgprgEan0S736aKjdk2 failed: Missing or insufficient permissions.
I am using anonymous log ons
even when I use the following rules which is supposed to allow all reading and writing of the data I get the same error:
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
I allowed several minutes to go by between when I set the permissions and before testing. Thanks.
Have you tried the default rule with timestamp :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if
request.time < timestamp.date(2023, 11, 25);
}
}
}

Not able to access a firebase collection after publishing security rule

I was trying to access data from Cloud Firestore, but the access is denied.
My flutter code
FirebaseAuth _auth = FirebaseAuth.instance;
final logineduser = _auth.currentUser!.uid;
final QuerySnapshot result = await FirebaseFirestore.instance
.collection('product_details').get();
final List<DocumentSnapshot> documents = result.docs;
print(documents[0]);
The Cloud Firestore Security rules
rule_version='2'
service colud.firestore{
match /databases/{database}/documents {
match /user_details/{emailId}{
allow read,write;
}
match /user_activities/{userId}{
allow read,write;
}
match /product_details/{Id}{
allow read,write;
}
match /purchase_details/{Id}{
allow read,write;
}
match /{document=**}{
allow read,write:if request.auth.uid !=null;
}
}
}
This says to allow read or write if the authentication is not null.. So unless the user is authenticated you will not be able to access data except for the queries you have written above this. You can either implement login or to make it public you can write
allow read,write;
Please note it is NOT a good practice to keep it public. Maybe for learning you can try this.

Combine firebase rules for facebook signin & normal sign up

I need to combine the rules for firebase firestore. If I use the standard method,
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
the usual method of registering users with a username, email and password works, & everething is perfect, and everything suits me.
But the facebook login method stops working. Most likely due to the fact that the user is not yet logged in to the server but is already trying to write data to the users collection. As a result, I can see it in the list of authorized users, but in firestore, its email field remains nil. If I use the standard rule that allows everyone to write data from the Internet)(i know it's bad practice)
allow read, write: if true;
everything works fine. So I need to somehow add a rule that allows everyone to write data to my users collection? A trigger is used to create a document during registration
exports.createAccountDocument = functions.auth.user().onCreate(async user => {
const { uid, displayName, email } = user
const username = displayName;
const profileImageUrl = uid;
const str = username;
const qwery = [];
for (let i = 0; i < str.length; ++i) {
qwery[i] = str.substring(0, i + 1).replace(/\s/g, "").toLowerCase();
}
const keywords = qwery;
const bio = "";
return await admin
.firestore()
.collection("users")
.doc(uid)
.set({ bio, keywords, email, profileImageUrl, uid, username })
})
Maybe it will be correct like this?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
match /users/{document=**} {
allow read, write: if true ;
}
}
?
Code running in Cloud Functions using the server SDKs (including the Firebase Admin SDK) for Firestore always bypass security rules. The code you're showing here in the onCreate trigger will always be able to write to Firestore regardless of what you write in your security rules.
Security rules only apply to direct access from web and mobile clients. Your rules should focus on access controlled by Firebase Authentication.

Don't get the simplest FireStore security rule to work as if it would not find my file - though looks like examples

I don't get this running, no matter what I do. I have already removed all rules, nevertheless I get simulated read denied. I habe tried companies/4U4kZKXkr3rHA6B04S5K and /companies/4U4kZKXkr3rHA6B04S5K as location, copy pasted the document id and the collection multiple times, nothing... To me, it looks just like all the running examples, I found
What am I doing wrong?!
UPDATE: I used these rules before, which did not work:
match /databases/{database}/documents {
// the request object contains info about the authentication status of the requesting user
// if the .auth property is not set, the user is not signed in
function isSignedIn() {
return request.auth != null;
}
// return the current users entry in the employees collection
function getEmployeeData() {
return get(/databases/$(database)/documents/employees/$(request.auth.uid)).data
}
// check if the current user has access to specific company
function accessCompany(companyId) {
return isSignedIn() && getEmployeeData()['companyId'] == companyId;
}
// check if the current user has a specific role
function hasRole(role) {
return isSignedIn() && getEmployeeData()[role] == true;
}
// check if the user has any of the given roles (list)
//function hasAnyRole(roles) {
// return isSignedIn() && getRoles().keys().hasAny(roles);
//}
}
match /users/{user} {
// anyone can see a specific users profile data (name, email etc), in a real scenario you might want to make this more granular
allow get: if true;
// noone can query for users
allow list, create: if false;
// users can modify their own data
allow update, delete: if request.auth.uid == user;
}
match /employees/{user} {
// only allow admins to set roles. Of course a user should be able to retrieve its own designated roles
allow get: if request.auth.uid == user || hasRole('admin');
allow list: if hasRole('admin');
allow update: if hasRole('admin');
allow create, delete: if false;
}
match /companies/{document=**} {
allow get, list, create, update, delete: if true;
}
}
By default, no read and write access is allowed to any document. If you want to allow access to a document, you must have at least one rule that matches the query that would allow that access. If you have commented out all your rules, then I would expect no reads or writes to be allowed.
Minimally, adding a rule like this will allow read access to all documents in the companies collection:
match /companies/{id} {
allow read: if true;
}
I suggest reviewing the documentation on security rules to better learn how they work.

Firebase Security rules to restrict access on all paths but one?

Question:
For the different top-level firestore collections below, how to restrict access to all but one of the paths?
We are building a data schema in Firestore to support a chat app for teachers across multiple schools.
The top-level firestore collections include:
/siteAdminUsers
/schools
/schools/{schoolId}/teachers
/schools/{schoolId}/chats
Below is the security rules setup we are trying now - where we check for:
valid user auth
expected value exists in userClaim variable request.auth.token.chatFlatList
However, the read listener for /messages is being blocked.
Error message:
FirebaseError: [code=permission-denied]: Missing or insufficient permissions
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token != null
&& request.auth.token.chatFlatList.val().contains($discussionId);
}
}
Details
We are using cloud functions for all data read/write, so for almost every case we can just block all client access.
The one exception is for the chat discussions, where we need to set a snapshot listener in the mobile client to know when there are new messages.
Sub-collection notes:
At a school, there are discussion sessions for school staff (teachers, admins, etc)
/schools/{schoolId}/chats/{discussionId}
Where each discussion-document contains:
list of participant teacher ids
subcollection for actual messages where each document is an indivual posted message:
/schools/{schoolId}/chats/{discussionId}/messages
User Claim code from Cloud Function
Looking at the cloud function logs, we have verified that the userClaim is being set.
return firebaseAdmin
.auth()
.setCustomUserClaims(
uid, {
chatFlatList: 'id1 id2 id3'
}
);
UPDATE #1
Tried the following variation where rules skip/omit the check on userClaim and auth.token.
However, still same permission error.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null;
}
}
}
I think the issue here is that you are writing a rule on the collection called messages.
All match statements should point to documents, not collections.
https://firebase.google.com/docs/firestore/security/rules-structure
You should try adding /{document=**} after your path to messages, something like:
match /schools/{schoolId}/chats/{discussionId}/messages/{document=**} {
allow write: if false;
allow read: if request.auth != null;
}
This worked for me if I wanted to read and write all collection but not one collection named "backStage";
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{collection}/{document} {
allow read: if true
allow write: if (collection != "backStage");
}
}
}
Here's a solution (seems to be working), which includes the check on chatFlatList user claim variable (from original question) for a substring :
match /schools/{schoolId}/chats/{discussionId}/messages {
allow write: if false;
allow read: if request.auth != null
&& request.auth.token.chatFlatList.matches(discussionId);
}
Figured this out thanks to:
Firebase storage rules based on custom parameters
Here the post shows there is not any $ notation to access the path var. I recall seeing this in a security rules example code example - maybe it's specific to database tiers?
https://firebase.google.com/docs/reference/security/storage/#string
https://regex-golang.appspot.com/assets/html/index.html
Trying some example inputs here, to get an understanding for how to create the regex's.