I am looking to anonymously connect to a Firestore and grab some data from a collection. This works perfectly fine under javascript, while it fails ("FirebaseError: Missing or insufficient permissions") under node.js. Any pointers will be appreciated.
This is the code that works without a hitch under javascript (I have omited the 'script' includes) and it returns data as expected:
var config = {
apiKey: "xxx",
authDomain: "xxx.firebaseio.com",
projectId: "xxx",
storageBucket: "xxx.appspot.com",
};
firebase.initializeApp(config);
firebase.auth().signInAnonymously().catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
console.log(error.message);
});
foo();
async function foo() {
var db=firebase.firestore();
var query = await db.collection("collection").limit(5).get();
query.forEach(function(doc) {
console.log(doc.data());
});
}
This is the code that does not work under node.js. The config/authdata is exactly the same as in the js example above. (It uses the firebase (client) library. My understanding is that the firebase-admin library does not allow anonymous signin.)
const firebase=require('firebase');
var config = {
apiKey: "xxx",
authDomain: "xxx.firebaseio.com",
projectId: "xxx",
storageBucket: "xxx.appspot.com",
};
firebase.initializeApp(config);
firebase.auth().signInAnonymously().catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
console.log(error.message);
});
let db = firebase.firestore();
db.collection('collection').get()
.then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, '=>', doc.data());
});
})
.catch((err) => {
console.log('Error getting documents', err);
});
The following error is triggered when db.collection('collection').get() is called. (earlier anonymous signing goes through)
Error getting documents { FirebaseError: Missing or insufficient permissions.
at new FirestoreError (/root/node_modules/#firebase/firestore/dist/index.node.cjs.js:1201:28)
at JsonProtoSerializer.fromRpcStatus (/root/node_modules/#firebase/firestore/dist/index.node.cjs.js:19708:16)
at JsonProtoSerializer.fromWatchChange (/root/node_modules/#firebase/firestore/dist/index.node.cjs.js:19955:44)
at PersistentListenStream.onMessage (/root/node_modules/#firebase/firestore/dist/index.node.cjs.js:16828:43)
at /root/node_modules/#firebase/firestore/dist/index.node.cjs.js:16757:30
at /root/node_modules/#firebase/firestore/dist/index.node.cjs.js:16797:28
at /root/node_modules/#firebase/firestore/dist/index.node.cjs.js:17844:20
at process._tickCallback (internal/process/next_tick.js:68:7)
code: 'permission-denied',
name: 'FirebaseError',
toString: [Function] }
Thanks again for any pointers!
One possibility is that you are actually not signed-in when you fetch Firestore. As a matter of fact the signInAnonymously() method is asynchronous and you don't wait that the Promise returned by this method resolves before fetching Firestore.
So, the following may solve your problem:
firebase.initializeApp(config);
let db = firebase.firestore();
firebase.auth().signInAnonymously()
.then(cred => {
return db.collection('collection').get()
})
.then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, '=>', doc.data());
});
})
.catch((err) => {
console.log(err);
});
Note that you should do the same in the JavaScript SDK version:
firebase.auth().signInAnonymously()
.then(cred => {
foo();
}}
.catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
console.log(error.message);
});
Related
I want to create a node js app which downloads some data from the firestore. Although I've done everything like it's shown in tutorials I've been stuck with reading document from the firestore for hours. I have a very simple database structure with simple security rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /partners/{document=**} {
allow read: if true;
}
}
}
In my code I just want to login into firebase using email and password and then download one document under existing path:
const firebase = require("firebase/app");
require("firebase/auth");
require("firebase/firestore");
const email = <correct email>
const password = <correct password>
var firestoreConfig = {
...
};
// Initialize Firebase
firebase.initializeApp(firestoreConfig);
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function(user){
const userId = user.user.uid
const firestore = firebase.firestore();
console.log(`logged to firestore as ${userId}`)
firestore.doc("/partner/test/communication/544a3deec/messages/2e5b89b8-c48f-4d4f").get()
.then(function(data){
console.log(`${Object.keys(data).length}`);
})
.catch(function(error){
console.log(error);
})
})
and the error is
{ FirebaseError: Missing or insufficient permissions.
at new FirestoreError (/Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:1205:28)
at fromRpcStatus (/Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:5246:12)
at fromWatchChange (/Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:5482:35)
at PersistentListenStream.onMessage (/Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:15817:27)
at /Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:15750:30
at /Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:15786:28
at /Users/cb/Documents/IdeaProjects/node-hello/node_modules/#firebase/firestore/dist/index.node.cjs.js:14218:20
at process._tickCallback (internal/process/next_tick.js:68:7)
code: 'permission-denied',
name: 'FirebaseError',
toString: [Function] }
I see that the login was successful because it printed out the uid of the user. What can be the issue ? Security rules or I just completely don't understand the firestore ?
EDIT:
Changed my code according to Doug answer:
firebase.initializeApp(firestoreConfig);
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
const userId = user.uid
const firestore = firebase.firestore();
console.log(`logged firestore as ${userId}`)
firestore.doc("/partner/test/communication/544a3deec/messages/2e5b89b8-c48f-4d4f").get()
.then(function(data){
console.log(`${Object.keys(data).length}`);
})
.catch(function(error){
console.log(error);
})
} else {
}
});
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error){
console.log(error);
})
same error as before
There is a typo in the code, an additional s for partner.
I want to get data from a Firestore Database, however, instead of getting an Array of 1 element, I get [Al] which I'm not sure what it is.
This is the code I have in my Index.html. I have changed the information inside the config object for security reasons here.
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-firestore.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "my api key",
authDomain: "demo",
databaseURL: "my url",
projectId: "my project",
storageBucket: "bucket",
messagingSenderId: "1051539927876",
appId: "my app id",
measurementId: "0000000000"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
firebase.analytics();
</script>
<script src="app.js"></script>
And this is what I have inside my app.js file
db.collection('cafes').get().then((snapshot) => {
console.log(snapshot.docs);
}).catch(err => {
console.log(err);
});
You need to do the following to get the data:
db.collection('cafes').get().then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
});
}).catch(err => {
console.log(err);
});
doc.data() will contain the data of the documents.
https://firebase.google.com/docs/firestore/query-data/get-data#get_all_documents_in_a_collection
var docRef = db.collection("cafes").doc("cafe_name");
docRef.get().then(function(doc) {
console.log("document data:", doc.data());
}).catch(function(error) {
console.log("Error getting data:", error);
});
or
db.collection("cafes").doc("cafe_name").get().then(function(doc) {
console.log("document data:", doc.data());
}).catch(function(error) {
console.log("Error getting data:", error);
});
You need to change "cafe_name" to the name of an item of cafes.
So I'm using VueJS with the PWA option enabled. When using Firebase Cloud Messaging (for web app), I'm getting a notification saying: This site has been updated in the background but Only when the tab is not focused or open. If the tab is active, I don't receive anything in the console.
I'm using Postman to send notifications for now, and it returns success
{
"multicast_id": 5364665067527599460,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1550148053476716%2fd9afcdf9fd7ecd"
}
]
}
Here is my main.js
const config = {
apiKey: "API_KEY",
authDomain: "AUTH_DOMAIN",
databaseURL: "DATABASE_URL",
projectId: "PROJECT_ID",
storageBucket: "STORAGE_BUCKET",
messagingSenderId: "SENDER_ID"
};
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.usePublicVapidKey("PUBLIC_VAPID_KEY");
navigator.serviceWorker.register('./firebase-messaging-sw.js')
.then((registration) => {
console.log("Now using registration: " + registration);
messaging.useServiceWorker(registration);
}).catch(err => {
console.log("Error in registration");
console.log(err)
});
My firebase-messaging-sw.js (I never saw the console log thats inside setBackgroundMessageHandler)
importScripts('https://www.gstatic.com/firebasejs/5.8.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/5.8.2/firebase-messaging.js');
var config = {
messagingSenderId: 'SENDER_ID'
};
firebase.initializeApp(config);
let messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('[firebase-messaging-sw.js] Received background message ', payload);
return self.registration.showNotification('title', {body: 'message'});
});
And in my App.vue (neither have I ever seen the console log in onMessage)
created() {
this.$messaging.onMessage(function(payload) {
console.log('Message received: ', payload);
// ...
});
},
methods: {
sendNotif() {
this.$messaging.requestPermission().then(() => this.$messaging.getToken())
.then((token) => {
console.log(token) // Receiver Token to use in the notification
})
.catch(function(err) {
console.log("Unable to get permission to notify.", err);
});
},
},
I can access the token, none of my configuration is wrong or else the postman request wouldn't give success. I've checked out several other questions related to this but no success so far...
I'm using firestore with react native like below, but while running my app data is not added to the cloud. am not sure why, please help me to understand the actual problem here.
componentWillMount() {
console.log('Test1');
firebase.initializeApp({
apiKey: 'xxxxxxx',
authDomain: 'testing-8ex763xxxxxxxxxxxxxx',
databaseURL: 'https://testing-8e76xxxo.com',
projectId: 'testing-xxxxx',
storageBucket: 'testing-8xxxxx.com',
messagingSenderId: '73664xxx042'
});
firebase.firestore().enablePersistence()
.then(function() {
// Initialize Cloud Firestore through firebase
var db = firebase.firestore();
console.log('Test3', db);
db.collection('us').add({
first: 'hai',
last: '111',
born: 1815
})
.then(function(docRef) {
console.log("Document written with ID: ", docRef.id);
})
.catch(function(error) {
console.error("Error adding document: ", error);
});
})
.catch(function(err) {
if (err.code == 'failed-precondition') {
// Multiple tabs open, persistence can only be enabled
// in one tab at a a time.
// ...
} else if (err.code == 'unimplemented') {
// The current browser does not support all of the
// features required to enable persistence
// ...
}
});
}
You have not given the reference of doc.
And also use 'set' instead of add method.
db.collection('us').doc('some_name').set({
first: 'hai',
last: '111',
born: 1815
})
I have setup Firebase to my Cordova App to authenticate with Facebook which works fine in Android due a workaround I have found. However, in my browser I can't make it work.
Problem: Once I call signInWithRedirect(provider) method its redirect to firebase and logs in correctly (checked on firebase's dashboard), then It redirects to my localhost:8000 but it never stops in getRedirectResult() method.
No console log errors displayed.
My app set up:
index.html
<script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.1.1/firebase-auth.js"></script>
app.js
var config = {
apiKey: "*********",
authDomain: "*********",
databaseURL: "*********",
projectId: "*********",
storageBucket: "*********",
messagingSenderId: "*********"
};
firebase.initializeApp(config);
login_controller.js
var provider = new firebase.auth.FacebookAuthProvider();
firebase.auth().signInWithRedirect(provider).then(function() {
firebase.auth().getRedirectResult().then(function(result) {
// This gives you a Google Access Token.
// You can use it to access the Google API.
var token = result.credential.accessToken;
// The signed-in user info.
var user = result.user;
console.log('result '+ result);
debugger;
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
debugger;
});
}).catch(function(error){
debugger;
});
Firebase configuration
localhost domain added
web env setup
Facebook auth setup
What did I miss?
I set it up like this (it is intertwined with a plugin I wrote):
This method gets called when it is identified that a user is not logged in:
toggleWebViewWithAuth: function () {
var win = function(d) {
console.log("web view toggled, going to auth");
auth.presentLogin().then(function() {
auth.getResult();
});
};
var fail = function(e) {
console.log(e)
}
cordova.exec(win, fail, "NavigationPlugin", "toggleWebView", []);
}
auth.presentLogin is an async function I made that looks like this:
presentLogin: async function () {
var provider = new firebase.auth.FacebookAuthProvider();
//provider.addScope('default');
provider.addScope('email');
//provider.addScope('pages_show_list');
return firebase.auth().signInWithRedirect(provider);
},
Also in the auth variable is:
getResult: function () {
firebase.auth().getRedirectResult().then(function(result) {
if (result.credential) {
// This gives you a Facebook Access Token. You can use it to access the Facebook API.
var token = result.credential.accessToken;
// ...
}
// The signed-in user info.
app.user = result.user;
console.log("result.user in presentLogin:", app.user);
}).then(function() {
//iosNav.getCurrentTabControllerName();
iosNav.toggleWebView();
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
alert("Error:", error);
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
}
So now go back and read the toggleWebViewWithAuth method that I posted, and you will see how I used it. This makes it so that getRedirectWithResult waits for signInWithRedirect. All of this can be configured outside of a plugin (without using cordova.exec, all that method does on the iOS side is open or close the UIWebView) - The most important part is that you just need to make sure to use my presentLogin method how I did to present it, calling getResult in the then block.
Also, for your js imports, firebase-app, and all of the firebase module js files, replaced using the global firebase.js import. You only need:
<script>.../firebase-app.js</script>
<script>.../firebase-auth.js</script>