Skip to main content

Receiving messages from nRF Cloud

This guide explains how to receive messages from nRF Cloud using the Message Routing Service. It walks you through the steps to create an HTTP server using Node.js and Express, and how to securely process messages sent from your team.

The Message Routing Service uses HTTP POST requests to send messages from devices on your team to your server.

Prerequisites and requirements

Make sure the following prerequisites and requirements are met before you proceed:

  • Have an nRF Cloud account.
  • Have an Owner or Admin role in your team.
  • Have one or more devices added to your team.
  • Have basic knowledge of programming.
  • An environment to run your server code (local machine or cloud service).
  • Ability to expose your server to the Internet (using tools like ngrok for local development).
  • Ability to make HTTP requests (using tools like curl).

Setting up the server

This section explains how to set up an HTTP server.

Using Node.js and Express

The following example uses Node.js and Express to set up an HTTP server:

  1. Download and install Node.js from the official website.

  2. Initialize your project:

    mkdir destination-server
    cd destination-server
  3. Create package.json:

    {
    "name": "webhook-server",
    "version": "1.0.0",
    "description": "Example destination for nRF Cloud Message Routing Service",
    "main": "webhook-server.js",
    "author": "Nordic Semiconductor",
    "license": "ISC",
    "dependencies": {
    "express": "^4.21.0",
    "body-parser": "^1.20.0"
    }
    }
  4. Create server.js.

    The following is an example of a simple Node.js server that:

    • Receives webhook requests.
    • Optionally verifies the authenticity of the message using the one or more of the x-api-key and x-nrfcloud-signature headers.
    • Sets the HTTP status code to 200 if authenticated or 401 if not.
    • Optionally sets the x-nrfcloud-team-id header to the team ID.

    The example reads a self-signed certificate for HTTPS communication. You can create such a certificate with (for example) a Linux command:

    openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -keyout private-key.pem -out certificate.pem

    This example uses Express, a popular web framework for Node.js, and the crypto module for signature verification.

    Change the lines under each "Set true to use this feature" and "Replace this with..." comment lines to reflect your use case and environment.

    // Example webhook destination for nRF Cloud Message Routing Service
    const express = require("express");
    const bodyParser = require("body-parser");
    const crypto = require("crypto");
    const https = require("https");
    const fs = require("fs");

    const app = express();
    const port = 8000;

    // Set true to use this feature
    const useApiKeyAuthentication = false;
    // Set true to use this feature
    const useSignatureAuthentication = false;
    // Set true to use this feature
    const useTwoStepVerification = false;

    // Replace this with your token if using API key authentication
    const token = "myToken";
    // Replace this with your secret key if using signature authentication
    const secretKey = "mySecretKey";
    // Replace this with your nRF Cloud team ID if NOT using two step verification
    const teamId = "8da963d3-f0f0-432d-a667-20bfdc0f314e";

    // Will be assigned at each message received
    let statusCode;
    let returnMessage;

    // Verify the API key in the request matches your token
    const verifyApiKey = (req) => {
    const reqToken = req.headers["x-api-key"];
    const verified = reqToken === token;
    if (!verified) {
    statusCode = 401;
    returnMessage = "Our token does not match API key in header";
    }
    return verified; // true or false
    };

    // Verify the signature in the request, using your secret key
    const verifySignature = (req) => {
    const signature = req.headers["x-nrfcloud-signature"];
    const body = JSON.stringify(req.body);

    // Create HMAC hex digest
    const hmac = crypto.createHmac("sha256", secretKey);
    hmac.update(body, "utf8");
    const digest = hmac.digest("hex");

    const verified = digest === signature;
    if (!verified) {
    statusCode = 401;
    returnMessage = "HMAC digest does not match header signature";
    }
    return verified; // true or false
    };

    app.use(bodyParser.json());

    app.post("/", (req, res) => {
    console.log("Got a POST to /, request contains:");
    console.log({
    headers: req.rawHeaders,
    url: req.url,
    method: req.method,
    params: req.params,
    query: req.query,
    body: JSON.stringify(req.body, null, 2),
    });

    let valid = true;
    if (useApiKeyAuthentication) {
    valid = verifyApiKey(req);
    }
    if (useSignatureAuthentication) {
    valid = verifySignature(req);
    }

    if (valid) {
    // Your logic here - process the request

    statusCode = 200;
    returnMessage = "Webhook POST request processed successfully";
    }

    // Finish processing
    if (!useTwoStepVerification) {
    res.set("x-nrfcloud-team-id", teamId);
    }
    res.status(statusCode).send(returnMessage);
    console.log("Response:", returnMessage);
    console.log({ statusCode: res.statusCode, headers: res.getHeaders() });
    });

    const options = {
    key: fs.readFileSync("private-key.pem"),
    cert: fs.readFileSync("certificate.pem"),
    };

    https.createServer(options, app).listen(port, () => {
    console.log(`Webhook running, listening on port ${port}`);
    });
  5. Install dependencies:

    npm i
  6. Run the server:

    node server.js
  7. Expose to the Internet (development only):

    ngrok http 8000

Use the provided https URL as your URL endpoint in nRF Cloud when you create a destination.

Setting up the HTTP destination in nRF Cloud

Complete the following steps to set up a new HTTP destination:

  1. Log in to the nRF Cloud portal.

  2. Select Device Management in the left navigation bar.

    A panel opens to the right.

  3. Select Message Routing Service.

  4. Create a new HTTP destination:

    1. Click Add Destination.

    2. Enter the URL provided by ngrok or your server's public URL (for example, https://your-ngrok-url.ngrok.io/webhook).

    3. Add an API token, secret, or both, depending on your changes to the server.js file.

      • For the above example, since it uses a self-signed certificate, turn off the Verify SSL feature.
    4. Click Create Destination.

Verifying your destination

If you edited your server.js script to change useTwoStepVerification to true, you must manually verify your destination, using either the portal or the REST API. See the verification sections of Using the nRF Cloud Message Routing Service for details.

Testing your destination

You can test your destination using the nRF Cloud portal as follows:

  1. Navigate to Message Routing.
  2. Click the icon in the Test column for your newly created destination. This sends a test message to your destination.

Testing API key authentication

If you edited your server.js script to change useApiKeyAuthentication to true and entered your token in the file, you can test the API key authentication feature.

After sending the test message described above, look for the x-api-key header in your server's message response. It should match the API key token you entered when creating your destination in nRF Cloud, and the token in your server.js.

Testing signature authentication

If you changed useSignatureAuthentication to true by editing your server.js script, and entered your secretKey in the file, you can test the signature authentication feature.

Sending a request with an incorrect signature using curl

Use the following curl command to send a request with an incorrect signature to your server:

curl -X POST -H "Content-Type: application/json" \
-H "x-nrfcloud-signature: incorrectsignature" \
-d '{
"type": "device.messages",
"timestamp": "2024-09-05T21:59:47.323Z",
"messages": [
{
"teamId": "test-team",
"deviceId": "test-device",
"messageId": "test-message",
"receivedAt": "2024-09-05T21:59:44.714Z",
"topic": "test/topic",
"message": {
"appId": "TEST",
"messageType": "DATA",
"data": "test data"
}
}
]
}' \
https://your-destination-url.com/webhook

Expected response:

The server responds with 401 Unauthorized and the message Invalid signature.

Sending a request with the correct signature

Instead of manually computing the signature, you can use the Test feature in nRF Cloud to send a test message to your destination. This test message includes the correct signature, allowing you to verify that your server accepts requests with a valid signature.

After sending the test message described above, review your server's message response. Verify that the message was received and that the signature was validated successfully.

Start receiving device messages

Now that you have tested the HTTP server and destination in nRF Cloud, you are ready to start receiving messages from your team's devices. MRS will not send messages to your destination until it has been verified.

Once the devices on your team begin sending messages to nRF Cloud, verify that they are also sent to your destination.