Firestore security rule not working - firebase

I have the following rule in my Firestore
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{documents=**} {
// Only the authenticated user who authored the document can read or write
allow read: if request.auth.uid == userId;
allow write;
}
}
}
which doesn't seem to work and i am using Rest API to get the data
For authentication I call:
https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=[API_KEY]
Once authenticated we get the idToken and pass as Authorization header for the next URL
https://firestore.googleapis.com/v1beta1/projects//databases/(default)/documents/users
The users collection has the id as the document name and the value is just a bunch of dummy keys.
When I run the client the error I get is
{u'status': u'PERMISSION_DENIED', u'message': u'Missing or insufficient permissions.', u'code': 403}
If i hardcode the value of the userid it works. So the value returned in {userid} does not seem to match the UID for some reason.
Can someone please help decode why this is happening?
Thanks
Rams

you don't need the document=** selector
service cloud.firestore {
match /databases/{database}/documents {
// dissallow all access
match /{documents=**} {
allow read, write: if false;
}
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
https://firebase.google.com/docs/firestore/security/rules-conditions

Related

How to manage Firebase database security rules for Sign In for the first time when there is no user registered yet?

This is my database Rules:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /user/{userId} {
allow read, write: if request.auth.uid != null;
}
match /user/{userId} {
allow create, read, write, update, delete: if request.auth.uid == userId;
}
match /{document=**} {
allow create, read, write, update, delete: if request.auth.uid != null;
}
}
}
As you can see user must have to get an auth.uid to get access into the documents of my database.
match /{document=**} {
allow create, read, write, update, delete: if request.auth.uid != null;
}
But the problem is when I have no user registered on my Authentication (And in Document /user/{userId}) and somebody try to sign in, I can not get any response for the limitation of permission. How should I set my security rules where I can check if a user actually exists or not in Sign In process?
P.S: It's working perfectly if I have at least one user registered on my auth.
Security rules don't know or care if there are any users registered with your app. They just make requirements about how the data can be accessed. If your rules require a signed-in user, then that's the requirement - there's no getting around it.
If some of your data must be accessible without being signed in, then you can't have a requirement that request.auth be populated with user data.
With the suggestion of Doug Stevenson, I removed request.auth.uid from /user/{userId} and erase read from same node on the next check and it is working.
Thanks a lot.
Full answer is:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /user/{userId} {
allow read;
}
match /user/{userId} {
allow create, write, update, delete: if request.auth.uid == userId;
}
match /{document=**} {
allow create, read, write, update, delete: if request.auth.uid != null;
}
}
}

How to use wildcards in firebase security rules

I'm trying to use a wildcard in my firebase security rules but it's not working like the online documentation describes.
I want to return the entire itineraryList collection but the security rules aren't working.
match /itinerary/{userId=**}/itineraryList/{doc} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId;
}
What is the correct syntax here to give authenticated users access to the entire list?
Update following your comments:
If you want to give read access to any authenticated user to all documents under the itinerary collection (including sub-collections), do as follows:
service cloud.firestore {
match /databases/{database}/documents {
match /itinerary/{docId=**} {
allow read: if request.auth.uid != null;
}
//possibly add another rule for write
}
}
Initial answer:
This is because by doing {userId=**} you are using the "recursive wildcard syntax", see https://firebase.google.com/docs/firestore/security/rules-structure#recursive_wildcards. It will correspond to the "entire matching path segment".
You should do:
service cloud.firestore {
match /databases/{database}/documents {
match /itinerary/{userId}/itineraryList/{doc} {
allow read: if request.auth.uid == userId;
allow write: if request.auth.uid == userId;
}
}
}
You may also watch this official Firebase video about Firestore security rules, it explains this point, among others: https://www.youtube.com/watch?v=eW5MdE3ZcAw

How to set Firestore security rules? resource.data: Null value error

I need some help making my security rules for firestore work.
These are my firestore rules:
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderID} {
allow read, update: if request.auth.uid == resource.data.buyerId || request.auth.uid == resource.data.sellerId;
}
}
}
my orders collection:
orders: {
sellerId: 'some-id',
createdAt: timestamp,
buyerId: 'some-id'
}
It should return all documents from orders collection which has either buyerId or sellerId equal to authorised user (request.auth.uid).
but the above rule is not working as expected.
firestore collections screenshot
firebase simulator output
That error message is suggesting that the requested document was not actually present in the database. You entered "orders/{orderId}", which looks like you put a wildcard in the Location field in the simulator. That's not going to work. You need to enter the path to an actual document that exists if you want to test your rule that uses its field values.
resource.data: Null - this error happens when you try to create a new entity.
Split write rule, on create and update.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /user/{userId} {
allow read: if request.auth.uid == userId;
function authed() {
return request.auth.uid == userId;
}
allow create: if authed() && request.resource.data.keys().hasOnly(['name']);
allow update: if authed() && request.resource.data.diff(resource.data).changedKeys().hasOnly(['name']);
allow delete: if authed();
}
}
}

Cloud Firestore Security Rules documentation example

This documentation page: Writing conditions for Cloud Firestore Security Rules, says the following:
Another common pattern is to make sure users can only read and write their own data
And provides this example:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
I don't understand why the create rule is not defined with the same condition as the rest, if request.auth.uid == userId, but instead is defined with if request.auth.uid != null. As I understand it, with this rule any user can create any document inside users, but cannot do anything with it unless it matches his uid. So why allow it at all?
Let's talk about the very basic security rule that could be implemented (with user authentication):
allow read, update, delete: if request.auth.uid != null;
allow create: if request.auth.uid != null;
where any user can delete the documents of another people creation. So to restrict/control it, we implement as shown in the code snippet provided.
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
The code snippet is just an example use case that uses different conditions for reference purposes as this is a tutorial/guide, so the Firebase team try to fit as many possible conditions to the code snippet.
You can, of course, do allow create: if request.auth.uid == userId; to strictly restricted to that particular user.
I hope it gives you some idea!

Firestore security rules allow user access to their data

I want to write a rule like this:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
That is, I want to allow all read and write operations to all of a user's data if that user is the authenticated user.
Unfortunately that does not work. I get an error specifying that I don't have permission to access the data.
This code solved the problem:
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth.uid == userId;
match /{document=**} {
allow read, write: if request.auth.uid == userId;
}
}
}
}
I think it's because you need to grant access to /users/{userId}, as well as /users/{userId}/{anyDoc=**}.
From the official documentation:
Another common pattern is to make sure users can only read and write
their own data:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches name of the user
// document. The wildcard expression {userId} makes the userId variable
// available in rules.
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
If your app uses Firebase Authentication, the request.auth variable
contains the authentication information for the client requesting
data.
Please note that this only works if you have made a 'users' table in your database and populated it with users that are known to your application (possibly copied from FireBase's users section Authentication/users in the webconsole).
AfaIcs you cannot refer to the Firestore authenticated users table this way. I found this lack of information very confusing since all examples and Firestore documentation make you believe that you can access the users created through the webconsole this way, invariably resulting in an 'access denied' messages when trying to read from a users table...

Resources