I'm trying to restrict access to a collection based on a users "role" on the document as well as whether they're signed in.
Just checking if they are signed in works:
rules_version = '2';
function isSignedIn() {
return request.auth != null;
}
service cloud.firestore {
match /databases/{database}/documents {
match /workspaces/{workspace} {
allow read: if isSignedIn();
}
}
}
But I want to make it a bit more granular, I'm following this Google guide. When I configure it exactly the same my frontend client errors with FirebaseError: Missing or insufficient permissions. However, testing the rule in the Firebase portal works(?).
rules_version = '2';
function isSignedIn() {
return request.auth != null;
}
function getRole(rsc) {
return rsc.data.access[request.auth.uid];
}
function isOneOfRoles(rsc, array) {
return isSignedIn() && (getRole(rsc) in array);
}
service cloud.firestore {
match /databases/{database}/documents {
match /workspaces/{workspace} {
allow read: if isOneOfRoles(resource, ["owner", "viewer"]);
}
}
}
As mentioned, testing the rule via Firebase works, however when querying from my frontend app it fails.
// VueJS
let workspace = []
async fetchWorkspaces() {
const db = firebase.firestore();
await db.collection('workspaces').get().then(response => {
response.forEach(snapshot => {
this.workspaces.push(snapshot.data());
})
})
}
Database document
I've also tried storing the RBAC for each user as a document in a subcollection and using the following rule
allow read: if isSignedIn() && exists(/databases/$(database)/documents/workspaces/$(workspace)/users/$(request.auth.uid));
Still doesn't work. I can only seem to grant broad access (is signed in)
Related
I am having weird behaviors with my Firebase Firestore Rules recently.
I am protecting a collection like so:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function getRoles() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role;
}
function isAdmin() {
return 'admin' in getRoles();
}
match /registrationsRequests/{document} {
allow create: if true;
allow read, update, delete: if false;
}
match /users/{document} {
allow read: if request.auth.uid == document || isAdmin();
allow write: if request.auth.uid == document || isAdmin();
}
}
}
After I log in (and I check if the user is available with its UID), I fetch the user. But I receive the following error (both checks should return true => isAdmin() and document)
FirebaseError: Missing or insufficient permissions.
#edit: The query used
const usrDoc = await this.db.collection('users').doc(user.uid).ref.get()
I am trying to make a web app that displays different elements based on what permissions I give to a user.
All the permissions are stored in the the Cloud Firestore database at /users/{userId} in the field "permissions", which is an array containing the permissionId's.
In /photo_libraries/{libraryId} I have a field called permissionId, which is a string.
I now want to give users that have the right permissionId to be able to read the document in /photo_libraries/{libraryId} that has that permissionId.
I've tried this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
}
match /photo_libraries/{libraryId} {
allow read: if get(/database/$(database)/documents/photo_libraries/$(libraryId)).data.permissionId in get(/databases/$(database)/documents/users/$(request.auth.uid)).data.permissions;
}
}
}
But this doesn't seem to work, I'm quite new to the Firestore rules. Can anyone help me out?
P.S. This is how my database looks like:
This is the code I try to run:
const db = firebase.firestore(); const auth = firebase.auth();
auth.onAuthStateChanged(user => {
if (user) {
db.collection('photo_libraries').get().then(snapshot => {
// set up the UI
}, err => {
console.log(err.message);
});
} else {
// Logging out stuff
};
});
In the console I get the error message:
Missing or insufficient permissions.
Thank you,
Jonas
Try this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
}
match /photo_libraries/{libraryId} {
allow read: if resource.data.permissionId in get(/databases/$(database)/documents/users/$(request.auth.uid)).data.permissions;
}
}
}
But a better solution would be to add the persmissions array as a custom claim, then you dont need to call get.
When querying Firestore make sure you are only querying the documents you can actually access. Look for "rules are not filter" on google and you will get plenty of hits on SO and in the official Firebase documentation.
I'm trying to implement a Firebase Security Rule to give users access to a "Project" document.
I have a collection of projects and each project has a members collection with the UserIDs.
The User is authenticated.
My structure looks like this :
Structure
This is my Security Rule, but it's not working.
Can anyone help me ? What am I doing wrong ?
//Firebase Rule
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /projects/{projectID} {
allow read, get, write: if request.auth.uid != null && exists(/databases/$(database)/documents/projects/{project}/members/$(request.auth.uid));
}
}
}
//Flutter Call
Stream<List<ProjectModel>> getUserList() {
print("getUSer");
return FirebaseFirestore.instance.collection('projects').snapshots().map(
(snapShot) => snapShot.docs
.map((document) => ProjectModel(
name: document.data()['name'],
owner: document.data()['owner'],
description: document.data()['description']))
.toList());
}
Try the following Example :
Authenticated User that can read or write to Projects Collection :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /projects/{projectID} {
allow read, write: if request.auth != null && exists(/databases/$(database)/documents/projects/{projectID}/members/$(request.auth.uid));
}
}
}
Note : Inside Your Members Collection The Documents inside it must be Auth .uid Like the following Photo
I have the following firestore rules setup where I want to let anyone create a document in the suggestions collection, but only a certain user can update it. The rules look like this:
service cloud.firestore {
match /databases/{database}/documents {
match /suggestions/{sugg} {
allow create, read;
allow update: if request.auth.uid == 'abc123';
}
}
}
When I test this in the provided simulator, it works fine; however after waiting 30 minutes I test in my deployed app and I get the error:
Error: Missing or insufficient permissions.
In my app I'm doing an add() call on the suggestions collection. So in my rules where I specify allow create, that should be sufficient. I added read in case the returned document would count as a read.
Client: (AngularFire)
this.afs.collection('suggestions').add(sugg).then(() => {
this.submitted = true;
}, err => console.error('Firebase error:', err));
The issue was that Firestore couldn't try to match a uid when request.auth was null. The solution was to add some functions:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function isAdmin() {
return isSignedIn() && request.auth.uid == 'abc123';
}
match /suggestions/{sugg} {
allow create, read;
allow update: if request.auth.uid == 'abc123';
}
}
}
I'm self studying firestore and I could not figure out a way to only allow a user to update, delete or read only the collections added by them.
This is the structure I'm using:
I use firebase auth for user handing. I save the currentUser.uid as user_id in the database for each collection.
These are the rules I'm using
service cloud.firestore {
match /databases/{database}/documents {
match /tasks{
allow read, update, delete: if request.auth.uid == resource.data.user_id;
allow create: if request.auth.uid != null;
}
}
When I try to read/get the data I get Missing or insufficient permissions error.
I'm using the web api (JavaScript) for firestore. This is the code I'm using to read data.
function read() {
db.collection("tasks").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
var newLI = document.createElement('li');
newLI.appendChild(document.createTextNode(doc.data().task));
dataList.appendChild(newLI);
});
});
}
the error was in my JavaScript I was getting all without filtering by user
function read() {
let taskColletion = db.collection("tasks");
taskColletion.where("user_id", "==", firebase.auth().currentUser.uid).get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
var newLI = document.createElement('li');
newLI.appendChild(document.createTextNode(doc.data().task));
dataList.appendChild(newLI);
});
});
}
This is actually explained on the Firestore Documentation(I recommend reading it).
You're missing a wildcard after /tasks:
service cloud.firestore {
match /databases/{database}/documents {
match /tasks/{task} {
allow read, update, delete: if request.auth.uid == resource.data.user_id;
allow create: if request.auth.uid != null;
}
}
}