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

# Authentifier et autoriser des appareils en utilisant MQTT avec Auth0

> Comment authentifier et autoriser des appareils en utilisant MQTT avec Auth0.

MQTT est un protocole léger souvent utilisé par les appareils pour communiquer avec d’autres systèmes. Il est conçu pour le modèle de messagerie **publication/abonnement**. Vous pouvez en savoir plus sur [MQTT](https://en.wikipedia.org/wiki/MQ_Telemetry_Transport) sur Wikipedia.

D’une manière générale, il y a trois composantes :

1. Un `publisher` de messages.
2. Un `subscriber` de messages.
3. Un `broker` qui relie l’un et l’autre.

Il existe une notion de `topics` (également appelés `channels` ou `subjects`) auxquels les messages sont associés. Les sujets sont utilisés pour acheminer les messages entre les éditeurs et les abonnés.

Le protocole MQTT prend en charge un mécanisme d’authentification de base basé sur des `usernames` et des `passwords`. Ces identifiants sont envoyés avec le message `CONNECT`.

Cet article montre une intégration entre un agent MQTT basé sur nodejs : [mosca](https://github.com/mcollina/mosca) et [Auth0](https://auth0.com). Dans cet exemple, Auth0 est utilisé pour **authentifier** les `publishers` et `subscribers` auprès de l’agent, puis pour **autoriser** l’acheminement des messages.

<Frame>
  <img src="https://mintcdn.com/docs-dev-actions-triggers-prototype/7ZTj9ECBnaPth0zw/docs/images/fr-ca/cdy7uua7fh8z/1BAQm0lXvF7A3VqIciOagV/df7a6093017c7df53b7538d4053804b3/2023-09-22_13-15-29.png?fit=max&auto=format&n=7ZTj9ECBnaPth0zw&q=85&s=9f0a4388d4fe99daf64a04aece3261f5" alt="Diagramme de flux de données MQTT" width="858" height="514" data-path="docs/images/fr-ca/cdy7uua7fh8z/1BAQm0lXvF7A3VqIciOagV/df7a6093017c7df53b7538d4053804b3/2023-09-22_13-15-29.png" />
</Frame>

## Composants de la solution

### L’agent

**mosca** est facile à héberger et peut être intégré à d’autres serveurs. Pour les besoins de cet exemple, nous nous contentons d’héberger nous-mêmes un serveur **mosca** :

```javascript lines 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 );
});
```

Cela crée un serveur qui écoute les messages MQTT sur le port 9999. **mosca** vous permet de remplacer les trois fonctions utilisées pour authentifier et autoriser les opérations.

Dans cet exemple, nous utilisons un module très simple, `auth0mosca`, pour exécuter ces fonctions. Auth0 est connecté à **mosca**.

### Le module Auth0Mosca

Ce petit [module](https://www.npmjs.org/package/auth0mosca) fiournit les quatre fonctions utilisées par **mosca**, `authenticateWithCredentials`, `authenticateWithJWT`, `authorizePublish` et `authorizeSubscribe` :

```javascript lines 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` utilise [OAuth2 Propriétaire de ressource, attribution de mot de passe et d’identifiant](/docs/fr-ca/authenticate/protocols) pour authentifier l’agent et toutes les connexions qui lui sont adressées. Chaque fois qu’un `publisher` ou un `subscriber` envoie un message **CONNEXION** à l’agent, la fonction `authenticate` est appelée. Nous y appelons le point de terminaison Auth0 et lui transmettons le`username`/`password`. Auth0 le valide par rapport à sa base de données de comptes (c’est le premier`request.post` dans le code). En cas de succès, il valide et analyse le jeton Web JSON (<Tooltip href="/docs/fr-ca/glossary?term=json-web-token" tip="Jeton Web JSON (JWT)
Format standard de jeton d’ID (et souvent de jeton d’accès) utilisé pour représenter en toute sécurité des demandes entre deux parties." cta="Voir le glossaire">JWT</Tooltip>) pour obtenir le profil de l’appareil et l’ajoute à l’objet `client` qui représente soit le `subscriber` ou le `publisher`. Cela se produit dans l’appel `jwt.verify`.

Par convention, tous les appareils connectés à l’agent ont un compte dans Auth0.

Remarquez que le profil de l’appareil a également une propriété `topics`. Il s’agit d’un tableau contenant tous les sujets auxquels cet appareil particulier est autorisé à accéder. Dans la capture d’écran ci-dessus, le `thermostat-1a` sera autorisé à publier (ou à s’abonner) aux sujets `temperature` et `config`.

Les fonctionnalités `authorizePublish` et `authorizeSubscribe` vérifient simplement qu’un sujet particulier demandé est présent dans cette liste.

`authenticateWithJWT` attend un JWT dans le champ `password`. Dans ce cas, le flux est légèrement différent :

1. L’éditeur et l’abonné obtiendront un jeton
2. Ils se connectent à `mosca` en soumettant le JWT
3. `mosca` valide le JWT
4. Les messages sont envoyés et retransmis aux abonnés

<Frame>
  <img src="https://mintcdn.com/docs-dev-actions-triggers-prototype/M4OX-dUcWfCOjXvH/docs/images/fr-ca/cdy7uua7fh8z/38KV0HggAdQDkLxqZuAOph/e134f43c290d432064f288e549a59789/2023-09-22_13-15-47.png?fit=max&auto=format&n=M4OX-dUcWfCOjXvH&q=85&s=abe6585d97fb3c6c64979a93feca6e0a" alt="MQTT JSON Web Token Data Flow " width="858" height="482" data-path="docs/images/fr-ca/cdy7uua7fh8z/38KV0HggAdQDkLxqZuAOph/e134f43c290d432064f288e549a59789/2023-09-22_13-15-47.png" />
</Frame>

Les éditeurs et les abonnés obtiendront le JWT d’une manière ou d’une autre. Notez que l’agent n’a plus besoin de communiquer avec Auth0. Les JWT sont des artefacts autonomes qui peuvent être validés à l’aide du secret utilisé pour les signer.

### L’éditeur

Pour cet exemple, l’éditeur est un simple programme nodejs qui utilise le module `mqtt`, et ajoute les bons identifiants :

```javascript lines 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));
}
```

Bien entendu, le `username` et le `password` devront correspondre à ceux stockés dans Auth0.

### L’abonné

L’abonné est très similaire à l’éditeur :

```javascript lines 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);
  }
});
```

## Résumé

Cela montre à quel point il est facile d’utiliser Auth0 dans différents scénarios. Le magasin d’utilisateurs d’Auth0 est utilisé pour gérer les appareils. Bien entendu, des règles d’autorisation beaucoup plus sophistiquées pourraient être élaborées sur la base d’autres conditions : heure, lieu, device\_id, etc. Toutes ces règles seraient très simples à mettre en œuvre, soit au moyen d’attributs de profil supplémentaires, soit au moyen de règles. Cela montre également comment le profil Auth0 flexible peut être étendu pour prendre en charge des artefacts arbitraires (tels que les `topics` dans l’exemple).

Pour en savoir plus sur les règles, consultez [Règles d'Auth0](/docs/fr-ca/rules).

Il n’est jamais bon d’envoyer des identifiants (`username`/`password`) sur des réseaux non sécurisés. Il existe d’autres implémentations qui fournissent une sécurité au niveau du transport qui empêcherait le contenu des messages d’être révélé. **mosca** prend en charge TLS par exemple. Il est probable qu’un déploiement en production privilégie cette solution, à moins que tout le trafic se fasse dans un réseau fermé.

### Remerciements

Un grand merci à [Matteo Collina](http://www.matteocollina.com/) pour la relecture de cet article et pour la production de **mosca**.
