I am receiving the following error when triggering this cloud function: "Error unauthenticated".
I do not wish to allow unauthenticated calls to this cloud function.
The workflow is as follows:
User registers in app via firebase password authentication
Firebase Auth Credentials are created (firebase signs in user upon success)
Once the credentials have been created, the cloud function is triggered in the firebase auth callback.
At this point, the call should be authenticated, given it's being triggered in the firebase auth response.
However, it keeps erroring with
Error: unauthenticated
The user is authenticated at this point.
Any suggestions?
CLIENT CODE ->
const onRegisterPress = () => {
if (password !== confirmPassword) {
alert("Passwords don't match.")
return
}
setLoading(true);
//CREATE'S USER'S AUTH CREDENTIALS
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((response) => {
const data = {
...
}
//console.log(response);
return new Promise(async function(resolve, reject) {
await firebase.functions().httpsCallable('writeAccountUser')({
data
}).then((response) => {
console.log("Write Account User Response: ", response);
resolve(setLoading(false));
}).catch((error) => {
console.error("Cloud Function Error: ", error);
setLoading(false);
reject(error)
})
});
})
.catch((error) => {
alert(error)
});
}
CLOUD FUNCTION ->
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const firestore = admin.firestore();
exports.writeAccountUser = functions.https.onCall((data, context) => {
console.log("Incoming Data: ", data);
console.log("Incoming Context: ", context);
const clientData = data.data;
console.log("Client Data: ", clientData);
console.log("Account ID: ", clientData.accountID);
return new Promise(async function (resolve, reject) {
const accountsRef = firestore.collection('Accounts');
const usersRef = firestore.collection('users');
const now = new Date();
if (clientData.accountExists === true) {
console.log("Account Exists");
await accountsRef
.doc(clientData.accountID)
.update({
users: admin.firestore.FieldValue.arrayUnion(clientData.uid)
}).catch((error) => { console.error(error); reject(false) });
}
else {
console.log("Account Does Not Exist!");
const account_data = clientData.accountData;
const product_lines = clientData.productLines;
await accountsRef
.doc(clientData.accountID)
.set({
account_data,
product_lines,
users: [clientData.uid],
dateCreated: {
date: now,
timestamp: now.getTime()
}
}).catch((error) => { console.error(error); reject(false)});
};
const email = clientData.email;
const fullName = clientData.fullName;
const acceptTerms = clientData.acceptTerms;
const userData = {
id: clientData.uid,
email,
fullName,
accountID: clientData.accountID,
dateCreated: {
date: now,
timestamp: now.getTime()
},
lastUpdateFetch: {
date: now,
timestamp: now.getTime()
},
termsConditionsAccepted: acceptTerms
};
await usersRef
.doc(clientData.uid)
.set(userData)
.catch((error) => { console.error(error); reject(false) });
resolve(true);
});
});
Error ->
[Unhandled promise rejection: Error: unauthenticated]
at node_modules/#firebase/firestore/dist/rn/prebuilt.rn-f9cd27ba.js:12199:33 in
at http:///node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:169743:29 in _errorForResponse
at node_modules/#firebase/firestore/dist/rn/prebuilt.rn-f9cd27ba.js:12747:31 in yu
at node_modules/tslib/tslib.js:77:12 in
at http://REDACTED/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:120748:21 in
at http://REDACTED/node_modules/expo/AppEntry.bundle?platform=ios&dev=true&hot=false&minify=false:120702:31 in fulfilled
You can try refactoring the function as shown below:
const onRegisterPress = async () => {
if (password !== confirmPassword) {
alert("Passwords don't match.")
return
}
setLoading(true);
const response = await firebase.auth().createUserWithEmailAndPassword(email, password)
const data = {...}
const fnResponse = await firebase.functions().httpsCallable('writeAccountUser')({data})
console.log("Write Account User Response: ", response);
}
You can also create the account using the Admin SDK in the same function and log the user on your web app after the response. That'll ensure the Cloud function's action has been executed as well (just in case the function is not called after user sign up for any reason).
Related
I want to get only the document specified by where.
Store the email address registered in the uid property as a value in the Firestore at the time of new registration.
async signUp() {
const db = firebase.firestore();
await this.$store.dispatch('signUp', { username:this.username, email:this.email, password:this.password });
await db.collection('myData').doc(this.username).set({
uid: this.email,
email: this.email,
myWallet: 1000
});
this.$router.push('/home');
}
async signUp({ commit }, userInfomation) {
try {
await firebase
.auth()
.createUserWithEmailAndPassword(
userInfomation.email,
userInfomation.password
);
const user = firebase.auth().currentUser;
await user.updateProfile({
displayName: userInfomation.username,
});
commit('setUserName', user);
} catch (e) {
alert(e.message);
}
},
mutations: {
setUserName(state, user) {
state.userName = user.displayName;
},
actions: {
async getMyWallet({ commit, state }) {
const uid = state.updateUserName.email; //Information on the logged-in user is stored in updateUserName.
const db = firebase.firestore();
const doc = await db
.collection('myData')
.where('uid', '==', uid)
.get();
commit('getMyWallet', doc);
}
}
When I ran it, I got the error written in the title.
Is it written incorrectly?
Is there any other good way?
async getMyWallet({ commit }) {
firebase.auth().onAuthStateChanged(user => {
const uid = user.email;
const db = firebase.firestore();
const doc = db
.collection('myData')
.where('uid', '==', uid)
.get();
commit('getMyWallet', doc);
});
},
When I rewrote the getMyWallet part, I got a new error.
Error details: doc.data is not a function
I am new to Node.js and I am struggling with Promises even after reading the tutorials provided by other stackflow users. I have already spent a whole evening on this and I am looking for help. I get the following error " Function returned undefined, expected Promise or value". My code is below. What am I doing wrong? I also have a suspicion that I have to use await/async because it looks like my code is running through without waiting for the first get to complete.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
var db = admin.firestore();
exports.declinedRequest = functions.firestore
.document('requests/{requestId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const status = newValue.status;
const request = context.params.requestId;
var registrationToken;
var message;
if(status=="created") {
console.log('Checkpoint1 ',context.params.requestId);
newValue.friends.forEach(doc => {
console.log('Checkpoint 2: ', doc);
var usersRef = db.collection('users');
var query = usersRef.where('mobile', '==', doc).get()
.then(snapshotFriend => {
if (snapshotFriend.empty) {
console.log('Checkpoint3.');
return;
}
snapshotFriend.forEach(mobile => {
registrationToken = mobile.data().fcmToken;
console.log('FCM token =>', registrationToken);
if (!registrationToken) {
console.log('No fcmToken available');
return;
}
message = {
notification: {
body: "Request still available from " + newValue.requesterName,
sound: "default",
badge: 1
},
data: {
requestId: `${request}`
}
};
console.log('FCM token message created');
})
})
})
} else {
return;
}
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response)
})
.catch(function (error) {
console.log("Error sending message:", error);
})
})
Try the code below hope this will work.
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const Promise = require('bluebird');
const _ = require('lodash');
let db = admin.firestore();
exports.declinedRequest = functions.firestore
.document('requests/{requestId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const status = newValue.status;
const request = context.params.requestId;
if (status == "created") {
console.log('Checkpoint1 ', context.params.requestId);
allPromises = [];
newValue.friends.forEach(doc => {
console.log('Checkpoint 2: ', doc);
const usersRef = db.collection('users');
// query for each document return promise.
allPromises.push(queryForEachDocument(doc,request,usersRef));
});
return Promise.all(allPromises);
} else {
return Promise.reject / resolve('Whatever you want.');
}
})
function queryForEachDocument(doc,request,usersRef) {
let promiseInvoices = []
let registrationToken;
let message;
return usersRef.where('mobile', '==', doc).get().then((snapshotFriend) => {
if (_.isEmpty(snapshotFriend)) {
console.log('Checkpoint3.');
return Promise.reject(new Error('Your error'));
}
snapshotFriend.forEach(mobile => {
registrationToken = mobile.data().fcmToken;
console.log('FCM token =>', registrationToken);
if (!registrationToken) {
console.log('No fcmToken available for', newValue.requesterName);
// Do anything you want to change here.
return Promise.reject(new Error('No fcmToken available for',newValue.requesterName));
}
message = {
notification: {
body: "Request still available from " + newValue.requesterName,
sound: "default",
badge: 1
},
data: {
requestId: request
}
};
console.log('FCM token message created');
// send invoice for each registrationToken
promiseInvoices.push(sendInvoice(registrationToken, message))
});
}).then(() => {
return Promise.all(promiseInvoices);
})
}
function sendInvoice(registrationToken, message) {
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response)
})
.catch(function (error) {
console.log("Error sending message:", error);
})
}
I'm trying to send FCM using Firebase Functions, This is the code I'm using
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
admin.firestore().settings({
timestampsInSnapshots: true
});
var token = 'token_value';
var sender = 'sender_value';
var reciever = 'reciever_value';
var message = 'message_value';
var payload ='payload_value';
var db = admin.firestore();
exports.sendFollowerNotification =
functions.database.ref('/m/{messageid}')
.onCreate((snapshot, context) => {
console.log('v21');
message = context.params.messageid;
console.log('Message Id:', message);
reciever = snapshot.val().r;
console.log('Message reciever: ', reciever);
sender = snapshot.val().s;
console.log('Message sender: ', sender);
payload = {
data: {
id: `${message}`,
sender: `${sender}`
}
};
console.log('Payload Created');
var tokenRef = db.collection(reciever).doc('t');
console.log('Fetching Token');
tokenRef.get()
.then(doc => {
console.log('Fetching Token started');
if (!doc.exists) {
console.log('Token doesnt exist ');
} else {
token = doc.data().v;
console.log('Token data:', token);
}
console.log('End Then');
return token;
})
.catch(err => {
console.log('Error getting token', err);
}).then((token) => {
console.log('Sending FCM now');
admin.messaging().sendToDevice(token,payload);
return console.log('Successfully sent message:');
})
.catch((error) => {
console.log('Error sending message:', error);
});
})
The problem is that FCM is received with huge delay(about 40s), however fcm sent from Firebase Console is received almost immediately (about 2-3s).
Since I am an android developer and have no experience of Node.js, I believe that something is wrong with JS code. Help me by telling whats wrong or possible workaround.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
admin.firestore().settings({
timestampsInSnapshots: true
});
var db = admin.firestore();
function debugLogger(msg) {
// comment out to disable logging
console.log(msg);
}
function errLogger(err) {
console.log(err);
}
exports.sendFollowerNotification =
functions.database.ref('/m/{messageid}')
.onCreate((snapshot, context) => {
debugLogger('v23_stackoverflow');
const message = context.params.messageid;
debugLogger(`Message Id: ${message}`);
const reciever = snapshot.val().r;
debugLogger(`Message reciever: ${reciever}`);
const sender = snapshot.val().s;
debugLogger(`Message sender: ${sender}`);
const payload = {
data: {
id: `${message}`,
sender: `${sender}`
}
};
debugLogger('Payload Created');
let tokenRef = db.collection(reciever).doc('t');
debugLogger('Fetching Token');
return tokenRef.get()
.then(doc => {
debugLogger('Fetching Token started');
if (!doc.exists)
throw new Error("Token doesnt exist");
let token = doc.data().v;
debugLogger(`Token data: ${token}`);
return token;
})
.then(token => {
debugLogger('Sending FCM now');
return admin.messaging().sendToDevice(token, payload);
})
.then(() => {
debugLogger('Successfully sent message!');
return null;
})
.catch(err => {
errLogger(err);
})
})
I have a Cloud Function setup on Firebase that involved checking different parts of the Firestore Database and then sending a message via Cloud Messaging
Below is the JavaScript for the function in question:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().Firebase);
var db = admin.firestore();
exports.newMemberNotification = functions.firestore
.document('Teams/{teamId}/Waitlist/{userId}').onDelete((snap, context) => {
// get the user we want to send the message to
const newValue = snap.data();
const teamidno = context.params.teamId;
const useridno = newValue.userID;
//start retrieving Waitlist user's messaging token to send them a message
var tokenRef = db.collection('Users').doc(useridno);
tokenRef.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
const data = doc.data();
//get the messaging token
var token = data.messaging_token;
console.log("token: ", token);
//reference for the members collection
var memberRef = db.collection('Teams/'+teamidno+' /Members').doc(useridno);
memberRef.get()
.then(doc => {
if (!doc.exists){
console.log('user was not added to team. Informing them');
const negPayload = {
data: {
data_type:"team_rejection",
title:"Request denied",
message: "Your request to join the team has been denied",
}
};
return admin.messaging().sendToDevice(token, negPayload)
.then(function(response){
console.log("Successfully sent rejection message:", response);
return 0;
})
.catch(function(error){
console.log("Error sending rejection message: ", error);
});
} else {
console.log('user was added to the team. Informing them')
const payload = {
data: {
data_type: "team_accept",
title: "Request approved",
message: "You have been added to the team",
}
};
return admin.messaging().sendToDevice(token, payload)
.then(function(response){
console.log("Successfully sent accept message:", response);
return 0;
})
.catch(function(error){
console.log("Error sending accept message: ", error);
});
}
})
.catch(err => {
console.log('Error getting member', err);
});
}
return 0;
})
.catch(err => {
console.log('Error getting token', err);
});
return 0;
});
The issues I have with this are:
The code runs and only sometimes actually checks for the token or sends a message.
the logs show this error when the function runs: "Function returned undefined, expected Promise or value " but as per another Stack Oveflow posts, I have added return 0; everywhere a .then ends.
I am VERY new to node.js, javascript and Cloud Functions so I am unsure what is going wrong or if this is an issue on Firebase's end. Any help you can give will be greatly appreciated
As Doug said, you have to return a promise at each "step" and chain the steps:
the following code should work:
exports.newMemberNotification = functions.firestore
.document('Teams/{teamId}/Waitlist/{userId}').onDelete((snap, context) => {
// get the user we want to send the message to
const newValue = snap.data();
const teamidno = context.params.teamId;
const useridno = newValue.userID;
//start retrieving Waitlist user's messaging token to send them a message
var tokenRef = db.collection('Users').doc(useridno);
tokenRef.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
throw 'No such document!';
} else {
const data = doc.data();
//get the messaging token
var token = data.messaging_token;
console.log("token: ", token);
//reference for the members collection
var memberRef = db.collection('Teams/' + teamidno + '/Members').doc(useridno);
return memberRef.get()
}
})
.then(doc => {
let payload;
if (!doc.exists) {
console.log('user was not added to team. Informing them');
payload = {
data: {
data_type: "team_rejection",
title: "Request denied",
message: "Your request to join the team has been denied",
}
};
} else {
console.log('user was added to the team. Informing them')
payload = {
data: {
data_type: "team_accept",
title: "Request approved",
message: "You have been added to the team",
}
};
}
return admin.messaging().sendToDevice(token, payload);
})
.catch(err => {
console.log(err);
});
});
I have done authentication trigger, it's working fine. If someone delete their account I need to send to notification "this user deleted his account (email)" like that. Here is my code
const functions = require('firebase-functions')
//initialize the app
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
const ref = admin.database().ref()
//create user account function
exports.createUserAccount = functions.auth.user().onCreate(event => {
const uid = event.data.uid
const email = event.data.email
const newUserRef = ref.child(`/UserNotify/${uid}`)
return newUserRef.set({
email: email
})
})
//delete user account function
exports.cleanupUserData = functions.auth.user().onDelete(event => {
const uid = event.data.uid
const userRef = ref.child(`/UserNotify/${uid}`)
return userRef.update({isDeleted: true})
})
function sendNotification() {
console.log("Successfully sent");
var payload = {
notification: {
title: "User get deleted",
body: "sample#gmail.com"
}
};
admin.messaging().sendToDeveice(payload)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
})
}
You may have a typing error
admin.messaging().sendToDevice() and not sendToDeveice
check: https://firebase.google.com/docs/cloud-messaging/admin/send-messages