How to send push notifications to multiple devices using Firebase Cloud Messaging - javascript

I was findind a way to deliver push messages from my expressJS server to my ionic app and I found GCM. With GCM I could deliver the message passing a list of tokens, like this :
sender.send(message, {
registrationTokens: deviceTokens
}, function (err, response) {
if (err) console.error(err);
else console.log('response' + JSON.stringify(response));
});
But as I found that GCM became FCM I was trying to do the same using FCM, but no luck until now. I've heard about sending topics but I couldn't find an example.
Can anyone give an example on how send topic messages using FCM ?
my FCM code: (working with just 1 token)
var FCM = require('fcm-node');
var serverKey = 'xxx';
var fcm = new FCM(serverKey);
var message = {
to: 'device-token',
notification: {
title: event.title,
body: event.information
}
};
fcm.send(message, function (err, response) {
if (err) {
console.log("Something has gone wrong! \n" + err);
} else {
console.log("Successfully sent with response: \n ", JSON.stringify(response));
}
});

I reckon you are using fcm push library for your push notification,
if you want to send same notification to multiple users then use "registration_ids" parameter instead of "to". this tag accepts an array of strings.
ex:
registration_ids:["registrationkey1","registrationkey2"].
note: limit is 100 key at a time.

I think it is documented pretty well by Google. Basically, there are two ways to send notifications to multiple groups:
Topic Messaging : You have the client subscribe to specific topics and then while sending notifications you just modify the request to target a specific topic. All the clients subscribed to that topic would receive the message.
POST request to this end point.
https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=SERVER_AUTHORIZATION_KEY
{
"to": "/topics/foo-bar",
"data": {
"message": "This is a Firebase Cloud Messaging Topic Message!"
}
}
How you subscribe to a specific topic depends on the device context. Documentation for Android and IOS are mentioned in the link I provide.
Device Groups : This is basically building on the approach you have provided you have the registration tokens of the devices you want to target. You can form a device group like so:
POST request
https://android.googleapis.com/gcm/notification
Content-Type:application/json
Authorization:key=API_KEY
project_id:SENDER_ID
{
"operation": "create",
"notification_key_name": "appUser-Chris",
"registration_ids": ["4", "8", "15", "16", "23", "42"]
}
The following request returns a notification_key which you can use in the to field to send notifications. Yes, You will have to save this notification_key somewhere and use it simply like:
POST request
https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=SERVER_AUTHORIZATION_KEY
{
"to": "aUniqueKey", //This is your notification_key
"data": {
"hello": "This is a Firebase Cloud Messaging Device Group Message!",
}
}
Ofcourse, you can add and remove devices from the group and all the other fine control. Like I mentioned, it is all documented very well and should get you started without a hiccup.

Related

Status Code 422 when trying to attach a file to an outlook calendar event

I'm trying to attach a text file to an existing Event in Outlook using graph-js-sdk-web.js I believe I followed instructions exactly but I get a 422 response. How do I get it to attach a file?
I'm pretty sure my eventID is correct because I can create an event and get it by that id. I'm pretty sure that my file's post load is correct because I attached file myself and then got that event by its id expanding for attachments and it was identical OData type, name, and content.
So far I googled the response and everything I've seen is either it just works for people or they were off on their code compared to that example.
Here are permissions I'm requesting
openid profile User.Read MailboxSettings.Read Calendars.ReadWrite
This matches permissions granted to the registered app.
This is the client and file attachment code:
// Create a Graph client
var client = MicrosoftGraph.Client.init({
authProvider: (done) => {
// Just return the token
done(null, sessionStorage.accessToken);
}
});
client
.api('/me/calendar/events/' + eventID + '/attachments')
.post({
attachment: {
"#odata.type": "#microsoft.graph.fileAttachment",
name: "helloworld.txt",
contentBytes: "SGVsbG8gd29ybGQh"
}
}, (error, response) => {
if (error)
console.log(error);
else {
console.log(response);
}
});
that produced this request payload
{
"attachment":{
"#odata.type":"#microsoft.graph.fileAttachment",
"name":"helloworld.txt",
"contentBytes":"SGVsbG8gd29ybGQh"
}
}
the response I get from this is
{
"error": {
"code": "UnprocessableType",
"message": "Cannot process input of abstract type 'Microsoft.OutlookServices.Attachment'",
"innerError": {
"request-id": "0a81e9f9-ef64-4b5e-b854-65e24fb71cfb",
"date": "2019-05-14T23:57:29"
}
}
}
I'm not seeing what does it need to process attachment. What I find odd is that its abstract base class, not the one I provided in the odata.type field, which could be nothing.
I opened graph explorer and even though they don't have a working sample for attaching to event I used a post with this payload and my url and got the exact same response 422. That tells me its not the js library its something off with the graph api itself, either setup is different from their documentation or we are missing some undocumented setup requirement.
Thanks to jasonjon's help the problem is solved. In the referenced instructions there's a mismatch in the payload example and javascript code sample. I went with js sample and had parent node attachment in the payload. Turns out there is no parent node. The correct way to use that api is
client
.api('/me/calendar/events/' + eventID + '/attachments')
.post({
"#odata.type": "#microsoft.graph.fileAttachment",
name: "helloworld.txt",
contentBytes: "SGVsbG8gd29ybGQh"
}, (error, response) => {
if (error)
console.log(error);
else {
console.log(response);
}
});

Firebase FCM error: 'InvalidRegistration'

I am currently trying to send a PushNotification to a Device Group using FCM with the help of Firebase Cloud Functions but once the notification is sent, it returns with code 200 but with failure :
SUCCESS response= {
multicast_id: 8834986220110966000,
success: 0,
failure: 1,
canonical_ids: 0,
results: [ { error: 'InvalidRegistration' } ]
}
Here is the code I am using to send this notification... what am I missing?
const options = {
method: 'POST',
uri: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Authorization': 'key=' + serverKey,
},
body: {
to: groupId,
data: {
subject: message
},
notification: {
title: title,
body: body,
badge: 1,
},
content_available: true
},
json: true
};
return rqstProm(options)
.then((parsedBody) => {
console.log('SUCCESS response=', parsedBody);
})
.catch((err) => {
console.log('FAILED err=', err);
});
Where JSON values title, body, subject, message are String
In my case, I was sending notifications to topic ("topics/my-topic"). I was missing prepending / in the starting of topic so I was getting the same issue. SO topic should be /topics/my-topic.
May be this helps!!
There is an easier way to send a message to a device group from a Cloud Function. Use admin.messaging().sendToDeviceGroup(). Sample code and instructions are in this guide.
I think your current method is failing because there is something wrong with the group notification key provided in groupId. It should be the string key value that was returned when you created the device group. The error codes are listed in this table. For 200/InvalidRegistration it says:
Check the format of the registration token you pass to the server.
Make sure it matches the registration token the client app receives
from registering with Firebase Notifications. Do not truncate or add
additional characters.
I was losing my mind with this InvalidRegistration error.
Eventually the problem was that I was subscribing my device to "example" but sending the notification json to: "example".
But we actually need to send to "/topics/example"
2 hours of my life wasted..
A registration token is tied to a certain group of senders. When a client app registers for FCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app.
Al you need to do is add a http header 'project_id' with your sender id.
I was getting InvalidRegistration:
Basic meaning: you are using the wrong token. Why? This may happen when you a new registrationToken is given to you in onNewToken (docs), but for some reason you are using the old token. That could happen when:
You're using a different push notification library which remembers token (stores it somewhere locally) and you didn't update that library with the new token.
Your application (or other library dependencies) implements another FirebaseMessagingService, and they conflict. Only one service can accept (react to) to the action sent by the FirebaseMessaging Android library's when a new token is given to it. You can double check this by opening the AndroidManifest.xml in Android Studio and selecting the Merged Manifest tab at the bottom of the tab. You can also place debuggers in each Service from each library you use. You'll see that only one service's onNewToken gets called.
When they conflict, one doesn't get the correct token, and the FCM registration token that gets registered would be wrong. Sending a message to a wrong registration, gets you InvalidRegistration.
for me, it was a mistake that I was passing an Id from my models instead of the tokens of the users
InvalidRegistration simply means that the token is either invalid or expired. You can uninstall the app and then reinstall and get a new token and then try with that token. This will definitely solve your problem.
You can read more here.

How to use batch notifications API with Cloud Functions for Firebase?

I'm just trying to have my app send a notification to the users when someone likes there event.
I have tried to do it this way:
exports.likeAddedNotification = functions.database.ref('/eventLikes/{eventID}/{userWhoLikedID}').onWrite(event => {
const userWhoLikedID = event.params.userWhoLikedID;
console.log("User has liked a post " + userWhoLikedID);
admin.database().ref('events/' + event.params.eventID).once('value').then(function(snapshot) {
var usersID = snapshot.val().userId;
console.log("The person who made the post is " + usersID);
//Send notification to that user
var payload = {
"group_id": "batch_push_sender",
"push_time": "now",
"message": {
"body": usersID + " liked your event"
},
"recipients": {
"custom_ids": [usersID]
},
"sandbox": true, // Only for iOS
};
notificationRequest.write(JSON.stringify(payload));
notificationRequest.end();
console.log("Sent a notification to " + usersID);
});
});
(Sorry for including so much code, but I feel it may all be relevant)
If I use this code and remove the
var payload = ...
and
notificationRequest.write(JSON.stringify(payload));
notificationRequest.end();
it works exactly how I'd expect. It will write to the console saying which post is liked and who liked that post.
I'm really not sure if the issue is coming from doing to much in a closure, or if I'm just doing something plain wrong, or if it's the Batch API that is causing errors.
If you know of a better site for push notifications that allows using a UDID as a custom identifier so that I don't have to manually deal with tokens for each device, please let me know!
First, make sure to return your Promises, that's the only way to guarantee that the Cloud Functions worker will keep things going. Since Firebase Cloud Notifications are sync, it's very likely your request is getting aborted.
You should also check out the Firebase Admin SDK's messaging components. We've built in some nice APIs for FCM.
We have an example on how to use these in Cloud Functions for Firebase on GitHub https://github.com/firebase/functions-samples/tree/master/fcm-notifications

AWS Cognito - Developer Authenticated Identities in JavaScript(Browser)

I have trouble getting credentials in a browser script.
The authentication server returns cognito_identityId and cognito_token.
Then I set a Cookie:
$.cookie('cognito_identityId')
$.cookie('cognito_token')
I tried to get credentials in 4 ways on the browser, and all Failed:
CognitoIdentityCredentials
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'us-east-1:xxxxxxxxxxxx'
IdentityId: $.cookie('cognito_identityId'),
Logins: {
'myauth': $.cookie('cognito_token')
}
});
// => Error: Missing required key 'IdentityId' in params
assumeRoleWithWebIdentity
var params = {
RoleArn: 'arn:aws:iam::xxxxxxxxxxxx:role/Cognito_xxxxxxxAuth_Role',
RoleSessionName: 'xxxxxxxxxxx',
WebIdentityToken: $.cookie('cognito_token'),
DurationSeconds: 900,
ProviderId: 'myauth'
};
var sts = new AWS.STS({apiVersion: '2011-06-15'});
sts.assumeRoleWithWebIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
// => AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity
PolicyDocument
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:xxxxxxxxxxxxx"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
]
}
GetCredentialsForIdentity
var params = {
IdentityId: $.cookie('cognito_identityId'),
Logins: {
"myauth": $.cookie('oauth.io_token')
}
};
var cognitoidentity = new AWS.CognitoIdentity({apiVersion: '2014-06-30'});
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
console.log(data); // successful response
}
});
// => InvalidParameterException: Please provide a valid public provider
WebIdentityCredentials
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: 'arn:aws:iam::xxxxxxxx:role/Cognito_xxxxxxxxxxAuth_Role',
WebIdentityToken: $.cookie('cognito_token')
});
// => Error: There were 2 validation errors:
// * MissingRequiredParameter: Missing required key 'IdentityPoolId' in params
// * MissingRequiredParameter: Missing required key 'IdentityId' in params
Questions:
What am I doing wrong?
What is the correct way to use this?
Thank you.
Thank you for your kindness.
I tyied your advice, but did not change.
Error messages.
POST https://cognito-identity.us-east-1.amazonaws.com/ 400 (Bad Request)
POST https://cognito-identity.us-east-1.amazonaws.com/ 400 (Bad Request)
Error: Missing required key 'IdentityId' in params
at fail (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2163:37)
at validateStructure (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2084:14)
at validateMember (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2110:21)
at validate (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:2059:10)
at Request.VALIDATE_PARAMETERS (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:800:32)
at Request.callListeners (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:3913:20)
at callNextListener (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:3903:12)
at chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:787:9
at finish (chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:126:7)
at chrome-extension://hmjdjbikinkmjbilihjibcihbkbjdgjf/bower_components/aws-sdk-js/dist/aws-sdk.js:142:9
There are source code below link.
https://github.com/bisque33/my-custom-dictionary
and server side is a AWS Lambda Function.
var aws = require('aws-sdk');
aws.config.region = 'us-east-1';
var cognitoidentity = new aws.CognitoIdentity();
var identityPoolId = 'us-east-1:0dccff0d-5fd7-4d14-b38f-d27204feaecc';
console.log('Loading function');
exports.handler = function(event, context) {
console.log('token: %s', event.token);
var params = {
IdentityPoolId: identityPoolId,
Logins: {
'oauth.io': event.token
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params,function(err,data){
if(err){
console.log(err);
context.fail('Something went wrong');
}else{
context.succeed(data);
}
});
};
This program is Google-Chrome-Extension.
AWS Lambda Function returns token by getOpenIdTokenForDeveloperIdentity.
app/scripts/popup.js calls Lambda Function and set cookies.
app/scripts/background.js calls AWS.config.credentials.get, and returns error.
Am I using it wrong?
Update for Additional Information
Thank you for the additional information.
Error appears on 104 line on background.js
AWS.config.credentials.get(function(){
and 115 line on background.js
dataset.synchronize(
And, My explaination was not enough. Facebook authentication needs the domain(ex. http :// example.com). However, Google-Chrome-Ext does not have domain. It has a domain 'chrome-extension://xxxxxxxxxxxxxxxxxxxx'. Then, I use https://oauth.io. It proxies any authentication and accepts chrome-extension domain.
Popup.js does Facebook authentication through oauth.io sdk. It gets a facebook token, and gives to getOpenIdTokenForDeveloperIdentity. I think facebook token.substr(0,14) is unique. But, If it is wrong, I use another unique identifier(ex. email-address.)
Sorry, I was wrong. AWS.config.credentials.get gives an Error:
Error: Invalid login token.
And, dataset.synchronize shows this Error:
Error: Missing required key 'IdentityId' in params
The first approach you have, using CognitoIdentityCredentials, is most likely the best approach for you to take. I can't spot exactly what's causing the error for you but lets try a couple things:
When using Developer Authenticated Identities, you do need to specify the IdentityId when initializing CognitoIdentityCredentials. You need to get the IdentityId value from the call to GetOpenIdTokenForDeveloperIdentity. However, you shouldn't need to preserve the IdentityId value in a cookie as CognitoIdentityCredentials will cache the id by default in the browser's local storage.
As for your Logins map: It looks like you're trying to use Developer Authenticated Identities. With the JavaScript SDK, use the key 'cognito-identity.amazonaws.com' and make sure the value is the token returned from your backend's call to getOpenIdTokenForDeveloperIdentity.
If you continue to have problem using the CognitoIdentityCredentials approach, please reply here with some more info such as the exact method/code you're calling when you receive the error message, and the traced output (i.e. with console.log('%o',..)) of the params input just before your call to the CognitoIdentityCredentials constructor.
Update Based on Additional Information Provided
I still need to know exactly which line of code you receive the error on, but based on the information provided I think I can still help...
Based on what I see in background.js, it looks like you're trying to initialize CognitoIdentityCredentials using a Developer Authenticated Identities provider. This is where I'm guessing that you're receiving the error.
However, in Popup.js, it looks like you're trying to authenticate the user with Facebook. If you're authenticating your users with Facebook, you should just pass the facebook access token into your Logins map when using Cognito. Just use graph.facebook.com as the key in the Logins map and the access token from Facebook. More detail on how to do this is in the Facebook Integration topic of the Amazon Cognito developer guide.
Facebook vs Developer Authenticated Identities
We can get Developer Authenticated Identities to work for you, but in this case, it doesn't look like the right solution for you since you're not actually doing any additional authentication on the identity in your Lambda function and the unique user identifier that you're passing into the getOpenIdTokenForDeveloperIdentity operation appears to be the facebook token, which is not good by the way since the token itself will change between user sessions even for the same user. Usually a good unique identifier is an email address or a user id used by an internal system.
Facebook Login & Redirects
Since you're ultimately trying to use Facebook for login and Amazon Cognito has built-in integration for Facebook, the best thing for you to do is get an access token from Facebook and pass in the Facebook token to Cognito's login map directly. I'm not sure if this will work with Auth.io or not (I'm just not familiar with it), but as long as Auth.io gives your JavaScript code a bonefide facebook token and you add the same Facebook App ID to both Auth.io and Amazon Cognito's Console, it should work. However, you mentioned you want to use Auth.io to avoid Facebook doing a redirect to a landing page. I could be mistaken, but I'm pretty sure if you're using Facebook's JavaScript SDK you won't need a redirect page. You should only need the redirect page if you're doing Facebook's Manually Build a Login Flow.

Sending Push Notification using javaScript in Parse

Actually we are done with sending push notification from mobile to mobile & parse to mobile using parse quires. Now we are trying to send push notification from web application to mobile device using Javascript.
function authentication() {
Parse.$ = jQuery;
// Initialize Parse with your Parse application javascript keys
Parse.initialize("app key",
"javascript key");
Parse.Push.send({
//where: pushQuery,
channels: [ "Demo","Done" ],
data: {
alert : "Hello word"
}}, { success: function() {
// Push was successful
alert : "Push was successful"
// debugger;
},
error: function(error) {
}}).then (function(error) {
//Marks this promise as fulfilled,
//firing any callbacks waiting on it.
});
}
Plz Guide us,we are new to javascript.
we getting error like this
POST https://api.parse.com/1/push 400 (Bad Request)
Did you activate Client Push Enabled in the Push Notifications settings of your Parse app ?
However, if you decide to send notifications from the JavaScript SDK outside of Cloud Code or any of the other client SDKs, you will need to set Client Push Enabled in the Push Notifications settings of your Parse app.
From: https://parse.com/docs/js/guide#push-notifications-sending-pushes
Note that you shouldn't send notification from any clients, instead trigger the notifications from cloud code
However, be sure you understand that enabling Client Push can lead to a security vulnerability in your app, as outlined on our blog. We recommend that you enable Client Push for testing purposes only, and move your push notification logic into Cloud Code when your app is ready to go into production.
I am also sending the notification from javascript to Mobile using parse.
My code is almost similar to you except one thing,
Instead of this
Parse.initialize("app key",
"javascript key");
I am using
Parse.initialize("APP_ID", "API_KEY", "JAVASCRIPT KEY");
My complete code is.. though I am using node.js you can relate to corresponding code.
var query = new Parse.Query(Parse.Installation);
query.equalTo('installationId', parseInstallationId);
Parse.Push.send({
where: query, // Set our Installation query
data: {
alert: "Willie Hayes injured by own pop fly."
}
}, {
success: function() {
// Push was successful
console.log('successful');
},
error: function(error) {
// Handle error
console.log('error');
}
});

Categories

Resources