Below are my Firestore rules. I have a "users" collection where the document ID is the user’s UID in the authentication. I want only admins to access some users data or the user itself.
service cloud.firestore {
match /databases/{database}/documents {
match /{users=**} {
allow read: if isOwner() || isAdmin();
allow write: if isOwner();
}
function isOwner() {
return request.auth != null && request.auth.uid == resource.id;
}
function isAdmin() {
return request.auth != null && request.auth.token.user_type == 3;
}
}
}
This is the function I use to fetch data:
const fetchUserDetails = async (userId: string) => {
const userDocRef = doc(FIREBASE_DB, 'users', userId);
console.log('Fetching userid: ', userId);
const userDocSnapshot = await getDoc(userDocRef);
if (userDocSnapshot.exists()) {
const userData = userDocSnapshot.data();
const addressesCollectionRef = collection(
FIREBASE_DB,
'users',
userId,
'addresses',
);
const addressesSnapshot = await getDocs(addressesCollectionRef);
const addresses = addressesSnapshot.docs.map(addressDoc =>
addressDoc.data(),
);
return {
...userData,
addresses,
};
}
// Handle the case where the user does not exist in Firestore
console.error('User not found in Firestore');
return null;
};
When I try the simulation in the Firestore everything works fine. Admin can get all users information and normal users only can get their information. But when I try to fetch user data with the above code in my React Native application, I get this error: FirebaseError: Missing or insufficient permissions. For the admin it works fine, it can fetch the data of itself. But regular user cant fetch its own data. I checked that regular user only trying to access its own data not others.
Also If I tried to change my security rules to this. Now even the admin cant fetch data.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if isOwner(userId) || isAdmin();
allow write: if isOwner(userId);
}
function isOwner(userId) {
return request.auth != null && request.auth.uid == userId;
}
function isAdmin() {
return request.auth != null && request.auth.token.user_type == 3;
}
}
}
3
Answers
So, I had a collection called "adresses" inside every user document and I was trying to fetch these users' adresses as well. But I did not consider it in my security rules. This is the working version of my rules. Everything is working as expected.
If you want
isOwner()
to work when you read data using the following lines of code:Then you have to change the rules to:
In this way, you will make sure your users will be able to only read and write their own data.
Please note that you can make your security rules cascade to nested sub-collections. So if you want to be able to read the data under the
addresses
sub-collection using the following lines of code:Then you have to specify a recursive wildcard
(=**)
in the match clause for the document ID. Since you do that for theusers
collection, your current access rules don’t cascade. So you have to use something like:Replace
resource.id
withresource.data.id
if what you want to access is theid
field of the fetched document.Note:
resource.id
andresource.data.id
will always return null if the document does not exist.