Apple push notifications on Amazon SNS from node.js

We’re going to hook up three things today: Apple Push Notification Service (APNS), Amazon Simple Notification Service (SNS), and node.js. This has the potential to be a mega-post, so instead, I’m going to write an annotated checklist. Maybe later I’ll turn it into a multi-part series.


Let’s talk about how all of these are hooked together. First, we want to send push notifications to iOS to alert users that something happened. We must use APNS to push to iOS. But eventually, we may want to develop an Android version of our app, but then we need to configure a Google app for that (Google Firebase can send push notifications to both iOS and Android). But our focus is on Amazon SNS, not to mention that SNS also supports Baidu cloud messaging and Windows Phone. To interface with SNS, Amazon has a node.js library called aws-sdk.

Setting up Apple Push Notifications
  1. Create an App ID in Apple Dev Center with “Push Notifications” enabled. Create a certificate for development and production and download them.
  2. Add the App ID to a provisioning profile.
  3. In XCode, go to the project settings. Update the provisioning profile. That should associate the push notification certificates with your app.
  4. In XCode, go to the project targets. Go to the “Capabilities” heading and enable “Push Notifications”. Then scroll down to “Background Modes”, enable it and check the box for “Remote notifications”.
  5. In app code, get the device token. I’m not going into detail here, but if you’re writing natively, use didRegisterForRemoteNotificationWithDeviceToken, or if you’re using the react-native-push-notification package, add a handler for onRegister: function(token) { … }

The iOS simulator cannot receive push notifications, so device token calls on the simulator will always fail.

Setting up Amazon SNS

First, a word about SNS concepts. There are multiple avenues for a user to be subscribed for notifications: Topics and applications. Topics are for broadcasting to a group of users subscribed to the same topic. Applications are for sending notifications to specific endpoints. In this case, we’ll use applications.

  1. From the AWS console, go to the SNS dashboard. Go to “Applications”, then “Create Platform Application”. Enter an application name, then upload the APNS certificate that you downloaded from step 1 of setting up APNS, above. After choosing the .p12 file (you may have to export it from Keychain Access), click “Load credentials from file”, then finish up by clicking “Create platform application”. Take note of the ARN of the newly created platform application; you’ll need it later.
Getting aws-sdk on node.js
  1. In your node.js project, run npm install aws-sdk --save.
  2. Configure your AWS credentials: on Linux/MacOS, create a file called ~/.aws/credentials. On Windows, create a file called C:\Users\USER_NAME\.aws\credentials. Hopefully you still have your AWS credentials from when you created your AWS account, because this should be contents of the credentials file:
    aws_access_key_id = YOUR_ACCESS_KEY_ID;
    aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
  3. At the top of your source files which will call SNS, add the following lines:
    var AWS = require('aws-sdk');
    AWS.config.update({region: 'us-west-2'});
    var sns = new AWS.SNS();

    Region should be filled in as appropriate. AWS calls will not work unless you configure the region.

Updating the device token from node.js

Before you chain all the SNS calls together, you might want to promisify them first. All the SNS calls are of the form sns.apiCall(params, callback) where params is an object containing the call parameters, and callback is a function(err, data). Promises are another topic I’m not going to detail, but here’s an example of a manually promisfied API – it will save you from Javascript callback hell:

function getEndpointAttributes(endpointArn) {
  return new Promise(function(resolve, reject) {
    var params = {
      EndpointArn: endpointArn
    sns.getEndpointAttributes(params, function(err, data) {
      if (err) {
  1. First, you should determine if you already have the user’s device token AND endpoint ARN stored someplace like your application database.
  2. If you don’t have the endpoint ARN, call sns.createPlatformEndpoint with the platform application ARN (step 1 from “Setting up Amazon SNS” above) and the user’s device token (you should code your mobile app to send this as a parameter),which will return the newly created endpoint ARN. The endpoint ARN is Amazon’s address for pushing notifications to your mobile app on a specific device. Save both the device token and endpoint ARN to some place like your application database.
  3. If you DO have the device token and endpoint ARN, compare the device tokens. Device tokens are mostly persistent, but are liable to changing once in a while. If the device token you received and the device token you stored are the same, there’s nothing else to do.
  4. If the device token you received and the device token you stored are different, then you need to delete the old endpoint by calling sns.deleteEndpoint with the old endpoint ARN, and then call sns.createPlatformEndpoint as detailed in step 2.
Sending a push notification
  1. Call sns.getEndpointAttributes with the user’s endpoint ARN. Make sure that the attributes have the “Enabled” property set to true, otherwise don’t send the notification.
  2. Call sns.publish with var params = { Message, Subject and TargetArn }. TargetArn should be the user’s endpoint ARN.

If the notification fails to send, the endpoint may have been silently disabled. SNS will disable an endpoint if the notification service (APNS or GCM) tells it that the device token is invalid. That may be caused by a bad certificate, or the device token expiring without a new one being uploaded for that user. To find out why, you can go to the SNS console, select your platform application, go to the “Actions” menu and select “Delivery status”. From that dialog, you can create an IAM role to log delivery failures to CloudWatch.

1 thought on “Apple push notifications on Amazon SNS from node.js”

Leave a Reply