Authenticating Node-RED with JSONWebToken

Published

Node-RED is great for power prototyping, but how do you keep the bad guys (or the general public for that matter) from using your endpoints without permission? When it's time to think of authenticating, JSONWebToken (JWT) is an elegant and simple way of checking your users' ID at the door.

Authentication doesn't have to be limited to HTTP and web calls. JSONWebToken can be used to authenticate data from any source. So if you want to start with HTTP, and move on to WebSockets or RabbitMQ later, you can authenticate using the same method.

Using JSONWebToken in Node-RED is a snap thanks to the node-jsonwebtoken node library and the node-red-contrib-auth node. In this first of a two-part article, we'll using these libraries to quickly and easily add cryptographically secure authentication to our Node-RED application. In the second part we'll show you how to use that with your Compose MongoDB database to create user authentication tokens.

Getting Started

You should have access to a running installation of Node-RED. If you already have Node.js on your local machine, you can use the terminal to install Node-Red: npm install node-red.

If you don't have Node.js yet, you can download the installer for your platform directly from the Node.js website.

Installing the node-red-contrib-auth Node

Node-RED is a flow-based programming (FBP) environment, so connecting to services requires access to a "node" that provides the services you need. In this article, we'll use the node-red-contrib-auth package, which installs a Node-RED node that can encode and decode data passed into it using the JSONWebToken spec. You can install it by selecting the Manage Palette option from the main menu, searching for the auth node and clicking install.

Encoding Data Into A JSONWebToken

We'll start by dragging an input node onto the Node-RED canvas. For now we'll use an http input node, but keep in mind that this can be done with any type of input node.

First, drag an HTTP input node onto the canvas and "double-click" it to configure. Set the URL of the node to /encrypt and the method to GET.

Next, we'll find the JWT node in the palette and drag that onto the canvas next to the HTTP input node. Double-click it to open the configuration panel, then click the pencil icon next to the drop down that says Add new JsonWebToken_config. Give the configuration a unique name, and enter a random set of characters in the secret section. You want the secret to be random and not guessable - this will serve as the key you use to encrypt and decrypt the JSONWebToken.

The JWT node will encode any data in the msg.payload object into a cryptographically secure JSONWebToken using the encryption secret you configured it with. Finally, it will pass that JSONWebToken to the output through the msg.token object, taking care to preserve the original msg.payload.

Since we want the JSONWebToken to be sent to the output node, let's add a change node here and transfer the msg.token over to the msg.payload. The change node contains a list of rules, with an initial rule that sets the msg.payload to an empty string. The rules contain three parts: the action, the value being set, and the value being received.

The "action", which can be one of Set, Change, Delete, and Move, determines how data will be transformed. For now, we'll leave this at the default of SET. The value being set will initially be the msg.payload object. We'll keep this for now and update the value being received to msg.token by clicking on the AZ dropdown, selecting msg, and typing payload in the text box.

Now, let's drag an HTTP Response output node onto the canvas. This will ensure that any requests made to the input node receive a response. When we access this route, any data passed into the HTTP input node as a query string parameter is automatically added to the msg.payload object. It will then pass through the JWT node and output an encrypted token, which will be returned in the response.

Decoding Data From JSONWebTokens

The JWT node will encrypt data passed into it on the msg.payload, but it will also attempt to decrypt JSONWebTokens passed into it in the msg.token object. To decode the token, you'll need to use the same key used to encrypt the original token.

For this example, we'll create an HTTP input node that will decrypt the JSONWebToken and return the decrypted data in an HTTP Response node. Drag an HTTP input node onto the canvas and double-click on it to configure. Set the URL of the node to /decrypt and the method to GET:

Then, drag the same JWT node onto the canvas next to the HTTP input node. Double-click it to configure the node and make sure to select the same configuration from the drop-down that you used to encrypt the token earlier.

So far, we have a JWT node waiting to decrypt any data passed into it via the msg.token object, and an HTTP input node which passes POST data in via the msg.req.body object. What we need now is a function node to transfer the appropriate parameter from msg.req.body to msg.token. Drag a new function node onto the canvas between the HTTP input node and the JWT node and double-click it and add the following code:

msg.token = msg.req.body.access_token;  
return msg;  

This assumes that the token you'd like to decrypt is sent in a JSON object that looks like the following:

{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiam9obiIsImlhdCI6MTQ4MDcyNjIzOH0.QMAH5MrAGbpnwr_mCycE3Qx_YKLujMxYDc1SNbfURtsckear"}

Since the decrypted value is put back on the msg.token object, we'll need to add a second function on the other side of the JWT node to transfer the decrypted values to the msg.payload object. Drag a new function node on the canvas and double-click it to add the following code:

msg.payload = msg.token;  
return msg;  

Finally, drag an HTTP Response output node onto the canvas and wire the nodes together.

You can test out our brand new JSONWebToken encoder / decoder using the following CURL commands, remembering to replace the values below with your own values.

$ curl -i -H "Accept: application/json" http://localhost/encrypt?name=john

which will encrypt the name into a JSONWebToken that looks similar to this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiam9obiIsImlhdCI6MTQ4MDcyNTg2NH0.Rz-0Smq_ulmriXLVO9weN_CnO4CnwPh35ktAbmAdhZg  

Decrypting looks something like this:

% curl -H "Content-Type: application/json" -X POST -d '{"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiam9obiIsImlhdCI6MTQ4MDcyODYxMH0.D0fU4Wg3wNeH0Ui9A0JU1_flFXNpvntk_LfqtCLsAOY"}' http://localhost/decrypt

and will output the value encoded within the token:

{"name":"john","iat":1480728610}

Finishing Up

This article represents a simple demonstration of securing data using JSONWebTokens in Node-RED. You can use JSONWebToken for encrypting sensitive information, such as user data, which need to be securely passed over insecure networks. In the next part in this series, we'll explore using JSONWebTokens to authorize and authenticate user actions in a Node-RED application using MongoDB on Compose.


If you have any feedback about this or any other Compose article, drop the Compose Articles team a line at articles@compose.com. We're happy to hear from you.

Image by Mike Wilson