I am using these rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Documents can only be read or written by authenticated users
match /{document=**} {
allow read, write: if request.auth != null && request.auth.uid == resource.data.uid;
}
}
}
From my understanding, this should mean: "Allow read or write operations ONLY IF the user is authenticated and their uid
matches the uid
of the document they are reading or writing".
Yet, I continually get permission-denied
errors.
This is the code I am using (Dart/Flutter):
static FirebaseFirestore instance = FirebaseFirestore.instance;
static CollectionReference colRef = instance.collection('someCollection');
With this wrapper method (updated):
Future<void> updateData() async {
final uid_ = FirebaseAuth.instance.currentUser!.uid;
final data = {'uid': uid_};
await colRef.doc(uid_).set(data);
}
Basically, I am passing the user uid
to the updateData
function, and ensuring the document has the same uid
so it conforms with the rules.
What am I doing wrong?
EDIT:
Things that I have tried:
Ensured that the user was authenticated and that the correct uid
was being passed to the wrapper function.
Used the set
method instead of the update
method to avoid any issues if the document does not yet exist.
Appended the uid
to the data
map after learning more about the resource
object.
Toggled the rules between request.auth.uid == resource.data.uid
and request.auth.uid == resource.id
.
Changed the rule to only be request.auth != null
, which ended up working as expected, but is a bit too broad for my comfort zone. Yet, this is proof that the user is authenticated. I just need a way to compare the auth.uid
with either the document.id
or uid
within the data map object.
Changed the wrapper method to explicitly use FirebaseAuth.instance
.
The specific error:
flutter: [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.
The key was that you're trying to write the uid
field for the first time.
Your rules now do this:
resource.data.uid
The resource
here refers to the document as it exists before the current operation, which doesn't seem to have the uid
value yet.
If you want to refer to the document as it'll exist after the write operation (if that write operation is allowed), use:
request.resource.data.uid
Also see the documentation on the resource
and request.resource
variables.