I'm trying to create a document in Firebase Firestore. I have manually added documents to it in the Web UI, but am unable to do it programmatically.
The following is a single HTML file, containing all the code, which is directly taken from the docs:
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-firestore.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "<REDACTED>",
authDomain: "<REDACTED>",
projectId: "<REDACTED>",
storageBucket: "<REDACTED>",
messagingSenderId: "<REDACTED>",
appId: "<REDACTED>"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
// example from the docs
db.collection("users").add({
first: "Ada",
last: "Lovelace",
born: 1815
})
.then((docRef) => {
console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
</script>
I have redacted the config object, but it was copied directly from the Firebase config page (furthermore, I know the config is correct because in another app (not pictured), Firebase Auth works just fine).
Upon opening the above HTML page, I get the following error in the console:
Error adding document: FirebaseError: Missing or insufficient permissions.
My Firestore security rules are as follows. They should be completely open to all reads and writes:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write, update, delete, create: if true;
}
}
}
Despite the "Missing or Insufficient Permissions" error, when I go to the "Monitor Rules" tab of the Firestore Rules page, I don't see any stats for the denied requests, as if the rules didn't even get evaluated at all, despite me having ran at least 50 requests over the last 24 hours:
Running simulated Firestore requests in the Firestore Rules Playground succeeds every time as expected, whether the request is "authenticated" or not.
Please advise, I am at a loss for what else to try.
I have sidestepped solving this issue by simply creating a new project. I still don't know what was wrong. Please see the comments below my question for possible solutions.
I spoke with Google support and found you need the
firebaserules.system IAM role. Here is what I received:
Thank you for contacting Google Cloud Support. My name is Sakshi and I will be helping you with this issue.
I understand that you are getting the error [1] on the existing Google project and want to debug this error without creating a new project. Please correct me if I have misunderstood the issue.
Please note that the service account or user account you are using to authenticate Firebase project need to have ‘firebaserules.system’ role, If you don’t have this role your security rules will deny all the incoming requests. I will suggest you refer to the document [2] to know more about this in detail.
If your application is using the server client libraries or the REST or RPC APIs, please note that they bypass all Cloud Firestore security rules and instead authenticate through Google Application default credentials. Please follow this document [3] to know about Firebase security rules.
I hope the provided information is useful. Please let me know if you have any questions regarding this issue.
Regards,
Sakshi
Google Cloud Support
[1] Firebase Firestore "Missing or insufficient permissions"
[2] https://cloud.google.com/firestore/docs/security/iam#security_rule_dependency_on_iam
[3] https://firebase.google.com/docs/firestore/security/get-started
Related
Hi I am trying in src>index.js
`
import {initializeApp} from 'firebase/app'
`
I am learning from a video. When the man in the video wrote this code, he wrote that it is being calculated next to him in green, but it does not write to me. and I think that's why when I try to pull data from firebase database I get the following error in the console
index.html:1 Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
Can anyone know the solution?
Your security rules do not allow anyone to read or write to your database. If you set your rule to true as shown below, it should allow you to write:
Sample:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /series/{document} {
allow read, write: if true;
}
}
}
To configure your Firestore Security Rules:
Firebase Console > Firestore Database > Rules (Tab) > Edit Rules > Deploy & Test
In this rule anyone can read or write to your series collection. I recommend reading about Firestore Security Rules to restrict access to authorized users only.
Thanks.
Your firebase firestore rules don't allow reads or write for the collection that you are trying to query from.
Goto Firebase console and modify the firestore rules
Docs: https://firebase.google.com/docs/firestore/security/get-started
I am running a node server with the firebase admin sdk. However, everytime I try to send a push notification from the server, I get a 401 error.
Here's the exact error I'm getting:
errorInfo: {
code: 'messaging/authentication-error',
message: 'An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions. See https://firebase.google.com/docs/admin/setup for setup instructions. Raw server response: "<HTML>\n' +
'<HEAD>\n' +
'<TITLE>PROJECT_NOT_PERMITTED</TITLE>\n' +
'</HEAD>\n' +
'<BODY BGCOLOR="#FFFFFF" TEXT="#000000">\n' +
'<H1>PROJECT_NOT_PERMITTED</H1>\n' +
'<H2>Error 401</H2>\n' +
'</BODY>\n' +
'</HTML>\n' +
'". Status code: 401.'
},
codePrefix: 'messaging'
I'm not exactly sure why I don't have permissions to the project. I have setup my service account, and downloaded the .json file. I even went into the gcloud platform and tried to add any permission that looked correct. Below are all the permissions associated with my service account:
I am running the server locally, and initialized the app like this:
const admin = require('firebase-admin');
const messaging = require('firebase-admin/messaging');
const serviceAccount = require('<path-to-key>');
const fbApp = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
projectId: '<PROJECT_ID>',
databaseURL: '<DB_URL>'
});
I am not sure what else to do as I've looked through the v1 documentation multiple times and still don't have any clue as to what permissions I'm lacking. I even made sure to "firebase login" into the correct google account to see if that could've been an issue.
Here's my code to send a message:
const sendPushNotifications2 = async (topic, reminder) => {
const payload = genPayload2(reminder);
//await messaging.getMessaging(fbApp).sendToTopic(topic, payload);
await admin.messaging(fbApp).sendToTopic(topic, payload);
};
I have verified the client_id, client_email, and private_key_id values in the .json file. I haven't yet verified the private_key property because I'm not sure where to find it.
It turns out that I had this API disabled: "Firebase In-App Messaging API"
It also turns out that this question was asked before, but I wasn't able to find it. Here's the answer
If anyone else runs into this issue this was my fix:
go to the google cloud platform website
go to APIs and Services
go to Enabled APIs & Services
click + Enable APIs and Services
search for Firebase In-App Messaging API and make sure it's enabled.
You can also just search for messaging and make sure that all the cloud messaging APIs are enabled.
The problem is that new Firebase projects have only the new "Firebase Cloud Messaging API (V1)" enabled by default, and with that configuration - the official firebase-admin NodeJS library will not be able to send messages and will get 401 PROJECT_NOT_PERMITTED errors.
To be able to send message from your server, you MUST also enable the older "legacy" API.
From your Firebase console, go to Project Settings and open the Cloud Messaging tab.
Make sure that both APIs listed are enabled - see screenshot of how it should look:
If any API is not enabled, for the API that is disabled click the three dots menu on the right and select "Manage API"
In the Google Cloud Console page that opens, click the "Enable" button.
Note:
This is basically the same answer as #Tial's self answer, but I was confused by it and (as commented) it got some things wrong - it took me a while to understand it (and the linked answer) to get it right, so I had to clarify.
Suddenly my code for adding new documents to Firestore is not working and not returning an error. I thought perhaps it was a network issue but Authentication and creating new users is working fine. My network connection is also quite solid.
[EDIT] I've switched on debug mode and a call to Firestore is made with a documentChange request and the correct data fields. The document is never created though. I am on the latest Firestore release.
I tried this simplified add to my collection:
firebase.firestore().collection('biff').add({
boff: 0,
baff: 5
}).catch(function(error) {
console.error('There was an error uploading a file to Cloud Storage:', error);
});
Here are my security rules: (I also tried completely public writing)
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
There are no error messages generated and the new document never appears in my collection. I can authenticate and create new users. Is it possible that authentication is live but somehow my firebase SDK thinks that there is no connection to firestore so its queueing up the documnent writes?
[UPDATE] I noticed that an earlier alpha version of my frontend was still able to write new documents. When I listed the projects firebase knew about in the CLI it listed an older firebase project. So I did 'firebase use --add' and chose my new firebase project and then did a 'firebase init' to reset everything except my index.html. I then did a 'firebase deploy' and lo and behold my deployed version is able to write new documents. My localhost version still is not able to write them though. So very odd. So I am half way there with a solution. All ideas welcome on whats happening on my local machine to stop writes still ...
Once I used a button instead of a form submit to trigger the routine with the document.add then it all worked from localhost, server and mobile. In the broken version the form would continue processing and leave the user in the main view in a state where that url and all urls afterwards had a parameter (?topic=Business) appended to them. From then on the document.add would no longer work. By moving to a button and using e.preventDefault it now works every time and all the urls remain clear. (no idea why this side effect wedged firestore add)
var postOfferElement = document.getElementById('postoffer');
postOfferElement.addEventListener('click', function(e) {
e.preventDefault();
saveOffer();
});
In saveOffer:
firebase.firestore().collection('offers').add({
created: firebase.firestore.FieldValue.serverTimestamp(),
owner: getUserID(),
name: getUserName(),
pic: getProfilePicUrl(),
completes: 0,
favs: 0,
offer: offerText,
topic: topicText,
exp: expText
});
I have set up a Firebase project that uses the Firestore database. i was given the following snippet to use it in my Javascript code:
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxx.firebaseapp.com",
databaseURL: "https://xxxxxxxxxxxxx.firebaseio.com",
projectId: "xxxxxxxx",
storageBucket: "xxxxxxxxx.appspot.com",
messagingSenderId: "xxxxxxxxx",
appId: "1:xxxxxxxxxxxxxxxxxxxxxxxxxxx"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
All was working to that point. I then needed to ensure that only my domain could use the app, by setting up authorized domains on the firebase project, as well as on the apiKey in the "credentials" menu from the Google Cloud Platform project.
My project still worked to this point, but I noticed that it still worked from any domain. So the restriction was not working. Actually, with more testing, I found out that the apiKey was not even necessary for my project to work, and I can reduce the snipet to the following and things still work:
// Your web app's Firebase configuration
var firebaseConfig = {
projectId: "xxxxxxxx",
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
So I am wondering: how can my project run and write in the Firestore database with only the projectId given? I am given a bunch of information in the snippet that is not even necessary.
Does anyone have an idea why this is happening to me? I tried to create a new project, following different tutorials again, with the same result. Actually, one of the tutorials I used has the same behaviour, as i can use this tutorial's project (it is actually online), just by specifying the projectId and I could make it's Firestoere quota run out by spamming it from my local server.
I can't find any information about a similar case to mine. Please help.
PS: here are my Firestore database rules, if it matters:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Every Firebase project is actually a Google Cloud project, and each cloud project has a unique ID. Since there can only be one Firestore instance per project, it's sufficient to use just the project ID to locate it.
Other values from the config file are used for other Firebase products. If you don't use those products, then you don't need them. Feel free to leave them out if that suits you. Bear in mind that you might run into problems in the future if you don't use the full configuration.
If you are concerned about the security of your Firestore instance, you should be using security rules to limit who can read and write what data. It's not possible to limit access to it based on the domain of your web app, or the location of the user. The rules you have right now allow anyone with an internet connection to create, modify, and delete any document in your Firestore instance. You might want to change that.
I am not sure where to begin but I recently saw 'Firebase' while searching for no server database, while it seems interesting to me, I was little worried about putting my api codes directly in the js files, which obviously can be seen through source but I have read that you can change the read/write rules and need authentication. so I no longer worried about API after reading through some pages
but the main question is:
I wanted to create an admin portal for my page, so example my admin page is located in localhost/admin/ <<< The page will simply have a login form which is to access the portal, so everything is set
var config = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: ""
};
firebase.initializeApp(config);
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
window.location = '/portal.html'
}
else {
// Do nothing
}
});
$("#loginbtn").click(function() {
var email = $('#login-name').val();
var password = $('#login-pass').val();
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
});
});
So when I log in successfully it will redirect me to that page but can someone just look through source code and then go that page manually and enter it?
Or even if I intend to build one page application and decide to change the page state after login, whatever functions i'm going to do after that, can someone still find out and inject the code ?
I'm not really expert on this but this what I was thinking before starting my project, so is there is any other way around?
If you want to add admin capabilities and you are using Firebase real-time database, you need to set some custom Firebase rules to only allow admins to access restricted data. So if a non-admin user signs in, they are unable to modify/access admin only data.
One way to do this with Firebase rules is to have a /whitelist node with uid1: "bojeil#bla.com", uid2: "puf#bla.com" for storing all whitelisted admin UIDs and then a top-level security rule for restricted admin only nodes like ".write": "auth != null && root.child('whitelist').child(auth.uid).exists()". It's fairly simple, but goes a long way.
If you are not using real-time database and building a traditional web application, you need to protect restricted admin only resources. You will need to send the Firebase ID token to your backend. You can do that by setting a session cookie with its value and making sure to update that session cookie every hour or so when the Firebase ID token is refreshed. When the cookie is sent with your request, you check for it, decode it (you can use the Firebase Admin SDKs for that) and check that the user it belongs to is an admin. If so, you can allow access, otherwise you block access. On every page, you would add an onAuthStateChanged listener. If that triggers with null, you redirect to the sign-in page. If the session cookie contains an ID token for a non-admin, you can do a HTTP redirect on your server to the user non-admin section.
tldr; you need to enforce the check on your backend by sending the Firebase ID token with the request and double checking its user has adequate privileges.