I am new to Firebase, right now i want to try Firestore php SDK and implement firestore auth rule. Current code below is work fine
use Google\Cloud\Firestore\FirestoreClient;
$db = new FirestoreClient();
$db->collection('mycollectionname')
->document('mydocumentname')
->set(['name'=>'aaa','value'=>'111');
Firestore auth rule
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
// before change
allow read, write: if true;
// after change
allow read, write: if request.auth.uid != null;
}
}
}
After change true to request.auth.uid != null, its give me error:
{ "error": { "code": 403, "message": "Missing or insufficient permissions.", "status": "PERMISSION_DENIED" } }
I can figure out to get user data like : email & password or user id token, how to solve above error using user data?
I just found it, maybe useful for anyone.
on file use Google\Cloud\Firestore\Connection\Grpc
I made some change :
......
......
private function addRequestHeaders(array $args)
{
$args += [
'headers' => []
];
$args['headers']['google-cloud-resource-prefix'] = [$this->resourcePrefixHeader];
///////// CODE THAT I ADD ///////////
if(session('user_token'))
{
$args['headers']['Authorization'] = ['Bearer '.session('user_token')];
}
///////// CODE THAT I ADD ///////////
// Provide authentication header for requests when emulator is enabled.
if ($this->isUsingEmulator) {
$args['headers']['Authorization'] = ['Bearer owner'];
}
return $args;
}
Using laravel, I made it to check the session, to add a Bearer token on header. After that using example above i added a session before the Firestore function was used
use Google\Cloud\Firestore\FirestoreClient;
/// adding session
session(['user_token'=>'eyJhbGciOiJSUzI1................']);
$db = new FirestoreClient();
$db->collection('users')
->document('test#gmail.com')
->set(['name'=>'aaa','value'=>'111');
In the auth rule I can also make document rules according to the user's email name, where the user's email can be obtained with the token id that was added before. Example:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{email} {
allow read, write: if email == request.auth.token.email;
}
}
}
Hellow,
If you want implement FirestoreClient PHP Library in your backend, you should use a service account to allow your backend go through firestore rules, this way you can control users flow (with rules) and give complete access or limited access to your own backend code. You can see how to set up a service account in Google's quicstart documentation.
In this process you might have some issue while trying to configure the path to your service account key file. Which might throw this error:
Google\Cloud\Core\Exception\ServiceException:
{
"message": "Missing or insufficient permissions.",
"code": 7,
"status": "PERMISSION_DENIED"
}
If this happens to you see my response in this stackoverflow thread.
I hope it helps you and everyone having the same issue.
Related
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);
}
}
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 12 months ago.
Improve this question
I am using firestore and firebase auth and I am trying to add custom usernames to my app (I am following this courses, Next.js Firebase Full Course) that connect to the freebase emulator because it is still in development. I have this piece of code that runs in a useEffect that gets the current user uid and then fetch a document from firestore, then checks if it exits and if i does set the username state to the username in the do. Here is the code:
useEffect(() => {
let unsubscribe;
if (user) {
console.log(user.uid);
const ref = doc(db, "users", user.uid);
unsubscribe = onSnapshot(ref, (doc) => {
if (doc.exists()) {
setUsername(doc.data()?.username);
} else {
console.log("No such document!");
}
});
} else {
setUsername(null);
}
return unsubscribe;
}, [user]);
But I always get the error "next-dev.js?3515:32 Uncaught Error in snapshot listener: FirebaseError: false for 'get' # L5". I have tried changing the on snapshot to a get doc but that also gets the same error. I tried making it so it didn't connect to the emulator that fixed it. I'm not sure why but I like to use the firebase emulator. Is there anyway to fix this
Thanks in advance!
The error message “FirebaseError : false for ‘get’ #L5” is saying that security rules are denying the request at line 5 of your security rules. If you have curated your rules like below,
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
then line 5 has the error as you are not allowing read and write access to anyone.
To fix that you can either change your firestore rules to :
match /{document=**} { allow read: if true; allow write: if true; }
but this allows setting your rules to true to both read and write operations, which means that you allow anybody who knows your project ID to read from, and write to your database which is obviously bad, since malicious users can take advantage of it. It’s true that you can use these settings for a small amount of time for testing purposes, but never in a production environment.
So there is another option in which you can limit access to your database to a fixed amount of time. Today is 1.03.2021, we are limiting the access for exactly one day by:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.time < timestamp.date(2021, 3, 2);
}
}
}
The most important part when it comes to security rules is the Firebase Authentication, meaning that you can allow access only to the users that are authenticated to perform operations in your database. The rules should look like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
If you need a more granular set of rules, for instance, to allow only the authenticated users, who have the value of the UID equal to the value of UID that comes from to authentication process, to be able to write to their own document, then you should consider using the following rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null && request.auth.uid == uid;
}
}
}
A feature request is filed for this error message to be more precise like “FirebaseError: PERMISSION_DENIED because security rules returned false for 'get' # L5”
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.
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.
In Firestore I wan't to allow a read, if the targeted document does not exists. I have tried the following:
service cloud.firestore {
match /databases/{database}/documents {
match /reports/{report} {
allow read: if !exists(/databases/$(database)/documents/reports/{report});
}
}
}
It does not work, the respons is: Missing or insufficient permissions..
In case you're doing this server-side, you might instead query the document's existence using the admin SDK (firestore rules are only applied to the client SDK):
const snapshot = await adminFirestore.doc('reports/non-existent-item').get();
if (!snapshot.exists) {
// handle gracefully
}
This seems to be working.
allow get: if resource == null;