Am trying to send notifications to all registered users from firebase admin every 2 hours with pubsub schedule function
This is code am deploying in firebase functions
exports.scheduledFunction =functions.pubsub.schedule('every 2 hours').onRun((context) => {
console.log('This will be run every 2 hours!');
listAllUsers(undefined)});
function listAllUsers(nextPageToken) {
// List batch of users, 1000 at a time.
admin.auth().listUsers(1000, nextPageToken)
.then(function(listUsersResult) {
listUsersResult.users.forEach(function(userRecord) {
pushCheckMessageNotification(userRecord.customClaims['latest']);
});
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken);
}
})
.catch(function(error) {
console.log('Error listing users:', error);
});
}
function pushCheckMessageNotification(token){
const promise = [];
promise.push(admin.messaging().send(
{
data: {
body: "Test",
title: "Test",
chat: "CHECK_MESSAGES"
},
android:{
priority: "high"
},
token: '' + token,
}).then(() => {
console.log("Pushed notification.");
console.log("Notify Token", token);
}).catch(error => {
console.error("Notification push crash", error);
}));
}
The below error occurred sometimes and notification not pushed
{ Error: Error while making request: timeout of 10000ms exceeded.
at FirebaseAppError.Error (native)
at FirebaseAppError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseAppError (/user_code/node_modules/firebase-admin/lib/utils/error.js:122:28)
at /user_code/node_modules/firebase-admin/lib/utils/api-request.js:152:23
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
errorInfo:
{ code: 'app/network-timeout',
message: 'Error while making request: timeout of 10000ms exceeded.' },
codePrefix: 'app' }
Related
I want to use firebase to authenticate users and then firebase functions to insert users into Hasura but having problems with the firebase functions.
When I try to create a user from the app the "registerUser" function, which can be found below, it ends with an error:
Error detected in registerUser:
{"#type":"type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.Insight",
"errorGroup":"CLic1cmw6emOsAE",
"errorEvent":{"message":"Error: The uid must be a non-empty string with at most 128 characters.
at FirebaseAuthError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)\
at new FirebaseAuthError (/srv/node_modules/firebase-admin/lib/utils/error.js:147:16)
at AuthRequestHandler.AbstractAuthRequestHandler.setCustomUserClaims (/srv/node_modules/firebase-admin/lib/auth/auth-api-request.js:996:35)
at Auth.BaseAuth.setCustomUserClaims (/srv/node_modules/firebase-admin/lib/auth/auth.js:342:40)
at exports.registerUser.functions.https.onCall (/srv/index.js:32:18)
at func (/srv/node_modules/firebase-functions/lib/providers/https.js:272:32)
at corsHandler (/srv/node_modules/firebase-functions/lib/providers/https.js:292:44)\n at cors (/srv/node_modules/cors/lib/index.js:188:7)
at /srv/node_modules/cors/lib/index.js:224:17","eventTime":"2020-06-10T08:25:03.017Z","serviceContext":{"service":"registerUser","resourceType":"cloud_function"}}}
If I instead create a user directly via the firebase console my "processSignUp" runs
but ends with another error:
ReferenceError: fetch is not defined
at GraphQLClient.<anonymous> (/srv/node_modules/graphql-request/dist/src/index.js:108:25)
at step (/srv/node_modules/graphql-request/dist/src/index.js:44:23)
at Object.next (/srv/node_modules/graphql-request/dist/src/index.js:25:53)
at /srv/node_modules/graphql-request/dist/src/index.js:19:71
at new Promise (<anonymous>)
at __awaiter (/srv/node_modules/graphql-request/dist/src/index.js:15:12)
at GraphQLClient.request (/srv/node_modules/graphql-request/dist/src/index.js:98:16)
at exports.processSignUp.functions.auth.user.onCreate (/srv/index.js:60:25)
at cloudFunction (/srv/node_modules/firebase-functions/lib/cloud-functions.js:132:23)
at /worker/worker.js:825:24
I've tried pretty much everything I could think of. I've used https://hasura.io/jwt-config/ to setup the JWT on Heroku. I've triple checked passwords and graphQL endpoint. I have no problems with the mutations or query variables when I play around in hasura console but I'm unable to connect the firebase functions to hasura. Thanks in advance.
functions/index.js
...
const client = new request.GraphQLClient(
"https://app-name.herokuapp.com/v1/graphql",
{
headers: {
"content-type": "application/json",
"x-hasura-admin-secret": "Password",
},
}
);
...
// On register.
exports.registerUser = functions.https.onCall((data) => {
const { email, password } = data;
try {
const userRecord = admin.auth().createUser({ email, password });
const customClaims = {
"https://hasura.io/jwt/claims": {
"x-hasura-default-role": "user",
"x-hasura-allowed-roles": ["user"],
"x-hasura-user-id": userRecord.uid,
},
};
admin.auth().setCustomUserClaims(userRecord.uid, customClaims);
return userRecord.toJSON();
} catch (e) {
let errorCode = "unknown";
let msg = "Something went wrong, please try again later";
if (e.code === "auth/email-already-exists") {
errorCode = "already-exists";
msg = e.message;
}
throw new functions.https.HttpsError(errorCode, msg, JSON.stringify(e));
}
});
...
// On sign up.
exports.processSignUp = functions.auth.user().onCreate(async (user) => {
const { uid: id, email } = user;
const mutation = `
mutation($id: String!, $email: String) {
insert_users(objects: [{
id: $id,
email: $email,
}]) {
affected_rows
}
}
`;
try {
const data = await client.request(mutation, { id, email });
return data;
} catch (e) {
throw new functions.https.HttpsError("invalid-argument", e.message);
}
});
In the package.json for your functions, try changing the node engine to 10 and your grapql-request package to 1.8.2.
Following the Firebase SDK docs on https://firebase.google.com/docs/auth/admin/email-action-links#generate_email_verification_link and getting the following error, which makes little sense as the function is triggered from the server environment using the authenticated admin.auth().
Might anyone know what is causing the issue?
Error from admin.auth().generateEmailVerificationLink : { Error: There is no user record corresponding to the provided identifier.
at FirebaseAuthError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseAuthError (/srv/node_modules/firebase-admin/lib/utils/error.js:147:16)
at Function.FirebaseAuthError.fromServerError (/srv/node_modules/firebase-admin/lib/utils/error.js:186:16)
at /srv/node_modules/firebase-admin/lib/auth/auth-api-request.js:1201:49
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
errorInfo:
{ code: 'auth/user-not-found',
message: 'There is no user record corresponding to the provided identifier.' },
codePrefix: 'auth' }
The code is just this:
exports = module.exports = functions.firestore
.document("xxx/{docId}")
.onCreate(async (snap, context) => {
let yyy = snap.data();
let { uid, userData } = yyy;
console.log("from sendEmailVerification, uid, userdata: ", userData);
const actionCodeSettings = {
url: `${emailConfirmationUrl}`,
handleCodeInApp: false
};
return admin.auth().generateEmailVerificationLink(userData.email, actionCodeSettings)
.then(async (link) => {
console.log("uid from generateEmailVerificationLink and email: ", uid, userData.email)
await admin.firestore().collection('users').doc(uid).set({
verificationLink: link,
emailVerified: false
}, { merge: true });
return emailfunc.sendCustomVerificationEmail(userData.email, link);
})
.catch((err) => {
console.error("Error from admin.auth().generateEmailVerificationLink :", err);
return Promise.reject(err);
});
});
You read the user's email address from the database (Firestore). That user account, however, doesn't exist in Firebase Auth. It must also exist in Firebase Auth if you wish to use APIs like getUser() and generateEmailVerificationLink(). Having it only in Firestore is not enough.
I am working on a react application with express as a backend but the api for firebase authentication is not working.
I have tried testing it with Postman, but there;s internal server response coming(errorcode 500).
app.post('/signup', (req, res) => {
const newUser ={
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle
};
//TODO: validate user
firebase
.auth()
.createUserWithEmailAndPassword(newUser.email,newUser.password)
.then((data) => {
return res
.status(201)
.json({ message: `User ${data.user.uid} signed up successfully` });
})
.catch((err) => {
console.error(err);
return res.status(500).json({error: err.code});
});
});
I expect it to post my data to firebase users, but its showing me internal server error 500.
Server Log:
TypeError: firebase.auth is not a function
at app.post (/srv/index.js:78:14)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at next (/srv/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/srv/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
at /srv/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/srv/node_modules/express/lib/router/index.js:335:12)
at next (/srv/node_modules/express/lib/router/index.js:275:10)
at expressInit (/srv/node_modules/express/lib/middleware/init.js:40:5)
at Layer.handle [as handle_request] (/srv/node_modules/express/lib/router/layer.js:95:5)
From the logs... its evident that the firebase.auth is having the issue...
try this..
$ npm install firebase --save
$ npm install firebase-admin --save
Then initialize as so:
const firebaseapp = require('#firebase/app');
require('#firebase/auth');
const firebase = firebaseapp.firebase
firebase.initializeApp({…})
then your app might work like this:
app.post('/signup', (req, res) => {
const newUser ={
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle
};
//TODO: validate user
firebase
.auth()
.createUserWithEmailAndPassword(newUser.email,newUser.password)
.then((data) => {
return res
.status(201)
.json({ message: `User ${data.user.uid} signed up successfully` });
})
.catch((err) => {
console.error(err);
return res.status(500).json({error: err.code});
});
});
you can read more about this here
I am able to send the push notification without delivery_receipt_requested. On adding the delivery_receipt_requested field, I am getting error.
I want to update a field in the database whenever the notification is delivered to the device from Firebase cloud function.
Error sending message: { Error: Invalid JSON payload received. Unknown
name "delivery_receipt_requested" at 'message': Cannot find field.
at FirebaseMessagingError.Error (native)
at FirebaseMessagingError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:39:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:85:28)
at new FirebaseMessagingError (/user_code/node_modules/firebase-admin/lib/utils/error.js:241:16)
at Function.FirebaseMessagingError.fromServerError (/user_code/node_modules/firebase-admin/lib/utils/error.js:271:16)
at /user_code/node_modules/firebase-admin/lib/messaging/messaging-api-request.js:149:50
at process._tickDomainCallback (internal/process/next_tick.js:135:7) errorInfo: { code:
'messaging/invalid-argument',
message: 'Invalid JSON payload received. Unknown name "delivery_receipt_requested" at \'message\': Cannot find field.' },
codePrefix: 'messaging' }
my payload structure
var payload = {
delivery_receipt_requested:true,
notification: {
title: user,
body: snapshot2.val()
},
android: {
notification: {
sound: "default"
}
},
token: userToken
};
admin.messaging().send(payload)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
return 1;
})
.catch((error) => {
console.log('Error sending message:', error);
return 0;
});
return snapshot2.val()
}).catch(error => {
console.log("Error" + userToken2)
});
I am using firebase-admin to send a push notification via Cloud Functions, but I keep getting this error:
TypeError: admin.messaging(...).send is not a function
at exports.sendNotification.functions.database.ref.onWrite (/user_code/index.js:43:27)
at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:59:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:53:36)
at /var/tmp/worker/worker.js:700:26
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Any idea why it's not working? I am using firebase-admin version 5.9.1, so it is the latest version. It should include the .send function but it's still not working. I have uninstalled the plugin and re-installed it, but still, it did not work.
This is the code I am using:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert({
projectId: "xxx",
clientEmail: 'xxx#xxx.iam.gserviceaccount.com',
privateKey: '-----BEGIN PRIVATE KEY-----<KEY>-----END PRIVATE KEY-----\n'
}),
databaseURL: "https://xxx.firebaseio.com"
});
exports.sendNotification = functions.database.ref("xxx").onWrite((event) => {
console.log("notify");
const registrationToken = "xxx";
// See documentation on defining a message payload.
var message = {
notification: {
title: "You have a new service request",
body: "this is the main body"
},
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
return admin.messaging().send(message)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
What am I doing wrong?
It should be sendToDevice not send, maybe something like this :
var message = {
notification: {
title: "You have a new service request",
body: "this is the main body"
},
data: {
score: '850',
time: '2:45'
}
};
return admin.messaging().sendToDevice(registrationToken, message)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});