> ## Documentation Index
> Fetch the complete documentation index at: https://docs-dev-docs-event-stream-action-templates.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> How to authenticate and authorize devices using MQTT with Auth0.

# Authenticating & Authorizing Devices using MQTT with Auth0

MQTT is a lightweight protocol often used for devices to communicate with other systems. It is designed for the **publish/subscribe** messaging pattern. You can read more about [MQTT](https://en.wikipedia.org/wiki/MQ_Telemetry_Transport) on Wikipedia.

Generally speaking there are 3 components:

1. A `publisher` of messages.
2. A `subscriber` to messages.
3. A `broker` that connects one and the other.

There's a notion of `topics` (a.k.a. as `channels` or `subjects`) which messages are associated with. Topics are used to route messages between publishers and subscribers.

The MQTT protocol supports a basic authentication mechanism based on `usernames` & `passwords`. These credentials are sent with the `CONNECT` message.

This article shows an integration between nodejs based MQTT broker: [mosca](https://github.com/moscajs/mosca) and [Auth0](https://auth0.com). In this example, Auth0 is used to **authenticate** `publishers` and `subscribers` to the broker, and then **authorize** routing of messages.

<Frame>
  <img src="https://mintcdn.com/docs-dev-docs-event-stream-action-templates/0yESejeOU6QiEi-j/docs/images/cdy7uua7fh8z/1BAQm0lXvF7A3VqIciOagV/776a17e3372964acc3ac67a71a026e06/2023-09-22_13-15-29.png?fit=max&auto=format&n=0yESejeOU6QiEi-j&q=85&s=937373e00b9eae47a594305e6e05f291" alt="MQTT Data Flow Diagram" width="858" height="514" data-path="docs/images/cdy7uua7fh8z/1BAQm0lXvF7A3VqIciOagV/776a17e3372964acc3ac67a71a026e06/2023-09-22_13-15-29.png" />
</Frame>

## Components of the solution

### The Broker

**mosca** is straightforward to host and can be embedded in other servers. For the purpose of this sample, we simply self-host a **mosca** server:

```javascript lines expandable theme={null}
var mosca = require('mosca')
var Auth0Mosca = require('auth0mosca');

var settings = {
  port: 9999,
};

//'Thermostats' is a Database connection where all devices are registered.
var auth0 = new Auth0Mosca('https://eugeniop.auth0.com', '{Your Auth0 ClientID}', '{Your Auth0 Client Secret}','Thermostats');

//Setup the Mosca server
var server = new mosca.Server(settings);

//Wire up authentication & authorization to mosca
server.authenticate = auth0.authenticateWithCredentials();
server.authorizePublish = auth0.authorizePublish();
server.authorizeSubscribe = auth0.authorizeSubscribe();

server.on('ready', setup);

// Fired when the mqtt server is ready
function setup() {
    console.log('Mosca server is up and running');
}

server.on('clientConnected', function(client) {
  console.log('New connection: ', client.id );
});
```

This creates a server listening for MQTT messages on port 9999. **mosca** allows you to override the 3 functions used to authenticate and authorize operations.

In this sample, we are using a very simple module `auth0mosca` to perform these functions. Auth0 is wired up to **mosca**.

### The Auth0Mosca module

This little [module](https://www.npmjs.org/package/auth0mosca) provides the 4 functions used by **mosca**, `authenticateWithCredentials`, `authenticateWithJWT`, `authorizePublish` and `authorizeSubscribe`:

```javascript lines expandable theme={null}
var request = require('request');
var jwt = require('jsonwebtoken');

function Auth0Mosca(auth0Namespace, clientId, clientSecret, connection)
{
  this.auth0Namespace = auth0Namespace;
  this.connection = connection;
  this.clientId = clientId;
  this.clientSecret = clientSecret;
}

Auth0Mosca.prototype.authenticateWithJWT = function(){

  var self = this;

  return function(client, username, password, callback) {

    if( username !== 'JWT' ) { return callback("Invalid Credentials", false); }

    // console.log('Password:'+password);

    jwt.verify(password, self.clientSecret, function(err,profile){
          if( err ) { return callback("Error getting UserInfo", false); }
          console.log("Authenticated client " + profile.user_id);
          console.log(profile.topics);
          client.deviceProfile = profile;
          return callback(null, true);
        });
  }
}

Auth0Mosca.prototype.authenticateWithCredentials = function(){

  var self = this;

  return function(client, username, password, callback) {
    
    var data = {
        client_id:   self.clientId, // {client-name}
        username:    username.toString(),
        password:    password.toString(),
        connection:  self.connection,
        grant_type:  "password",
        scope: 'openid name email' //Details: https:///scopes
    };

    request.post({
        headers: {
                "Content-type": "application/json"
            },
        url: self.auth0Namespace + '/oauth/ro',
        body: JSON.stringify(data)
      }, function(e,r,b){
        if(e){
          console.log('Error in Authentication');
          return callback(e,false);
        }
        var r = JSON.parse(b);

        if( r.error ) { return callback( r, false); }

        jwt.verify(r.id_token, self.clientSecret, function(err,profile){
          if( err ) { return callback("Error getting UserInfo", false); }
          client.deviceProfile = profile;
          return callback(null, true);
        });
    });
  }
}

Auth0Mosca.prototype.authorizePublish = function() {
  return function (client, topic, payload, callback) {
   callback(null, client.deviceProfile && client.deviceProfile.topics && client.deviceProfile.topics.indexOf(topic) > -1);
  }
}

Auth0Mosca.prototype.authorizeSubscribe = function() {
  return function(client, topic, callback) {
  callback(null, client.deviceProfile && client.deviceProfile.topics && client.deviceProfile.topics.indexOf(topic) > -1);
}

module.exports = Auth0Mosca;
```

`authenticateWithCredentials` uses the [OAuth2 Resource Owner Password Credential Grant](/docs/authenticate/protocols) to authenticate the broker and all connections to it. Each time a `publisher` or a `subscriber` send a **CONNECT** message to the broker the `authenticate` function is called. In it we call the Auth0 endpoint and forward the device's `username`/`password`. Auth0 validates this against its account store (that is the first `request.post` in the code). If successful, it validates and parses the <Tooltip tip="JSON Web Token (JWT): Standard ID Token format (and often Access Token format) used to represent claims securely between two parties." cta="View Glossary" href="/docs/glossary?term=JSON+Web+Token">JSON Web Token</Tooltip> (JWT) to obtain the device profile and adds it to the `client` object that represents either the `subscriber` or the `publisher`. That's done in the `jwt.verify` call.

By convention, all devices connected to the broker have an account in Auth0.

Notice that the Device Profile also has a property `topics`. This is an array with all topics this particular device is allowed to. In the screenshot above, `thermostat-1a` will be allowed publishing (or subscribing) to topics `temperature` and `config`.

The `authorizePublish` and `authorizeSubscribe` functions simply check that a particular requested topic is present in this list.

The `authenticateWithJWT` expects a JWT in the `password` field. The flow in this case is slightly different:

1. The publisher & subscriber will obtain a token
2. They connect to `mosca` submitting the JWT
3. `mosca` validates the JWT
4. Messages are sent and re-transmitted to subscribers

<Frame>
  <img src="https://mintcdn.com/docs-dev-docs-event-stream-action-templates/4qFzmJi6DiADu06-/docs/images/cdy7uua7fh8z/38KV0HggAdQDkLxqZuAOph/e134f43c290d432064f288e549a59789/2023-09-22_13-15-47.png?fit=max&auto=format&n=4qFzmJi6DiADu06-&q=85&s=556e1c7ccd93f0a248c9bda4cd849992" alt="MQTT JSON Web Token Data Flow " width="858" height="482" data-path="docs/images/cdy7uua7fh8z/38KV0HggAdQDkLxqZuAOph/e134f43c290d432064f288e549a59789/2023-09-22_13-15-47.png" />
</Frame>

Publishers and subscribers will obtain the JWT through some means. Notice that the broker doesn't need to communicate with Auth0 anymore. JWTs are self-contained artifacts that can be validated with the secret used to sign them.

### The Publisher

For this sample, the publisher is a simple nodejs program that uses the `mqtt` module, and adds the right credentials:

```javascript lines expandable theme={null}
var mqtt = require('mqtt')
  , host = 'localhost'
  , port = '9999';

var settings = {
  keepalive: 1000,
  protocolId: 'MQIsdp',
  protocolVersion: 3,
  clientId: 'Thermostat 1a',
  username:'thermostat-1a',
  password:'the password'
}

// client connection
var client = mqtt.createClient(port, host, settings);

setInterval(sendTemperature, 2000, client);

function sendTemperature(client){
  var t = {
    T: Math.random() * 100,
    Units: "C"
  };

  client.publish('temperature', JSON.stringify(t));
}
```

Of course `username` & `password` here will have to match whatever is stored in Auth0.

### The subscriber

The subscriber is very similar to the publisher:

```javascript lines expandable theme={null}
var mqtt = require('mqtt')
  , host = 'localhost'
  , port = '9999';

var settings = {
  keepalive: 1000,
  protocolId: 'MQIsdp',
  protocolVersion: 3,
  clientId: 'Reader-X1',
  username:'reader-X1',
  password:'the password'
}

// client connection
var client = mqtt.createClient(port, host, settings);


client.subscribe('temperature');

client.on('message', function(topic, message) {

  if(topic ==='temperature')
  {
    console.log('New reading', message);
  }
});
```

## Summary

This shows how easy it is to use Auth0 in various scenarios. Auth0's user store is being used to manage devices. Of course much more sophisticated authorization rules could be written based on other conditions: time, location, device\_id, and so on All these would be very simple to implement, either through additional profile attributes or through Rules. This also shows how the flexible Auth0 Profile can be extended to support arbitrary artifacts (such as `topics` in the example).

To learn more about Rules, you can review [Auth0 Rules](/docs/customize/rules).

Ιt is never a good idea to send credentials (`username`/`password`) over unsecured networks. There are other implementations that provide transport level security that would prevent message contents to be revealed. **mosca** supports TLS as an example. Likely a production deployment would favor this, unless all traffic happens in a closed network.

### Acknowledgements

Many thanks to Matteo Collina for the review of this article, and for building the awesome **mosca**.
