javascriptamazon-web-servicesmqttaws-iot-coremqtt.js

Connecting to MQTT on AWS IoT Core from browser


My goal is to create a web page where I can see (even just in the console, for now) messages that are posted on a specific topic of an MQTT broker that I have on AWS IoT Core. Being on AWS IoT Core is an important detail since you can only connect to it using certificates.

I was successfully able to connect to this broker and receive messages both with Python (using Paho MQTT) and Node.js (using MQTT.js). Now I'd like to be able to get messages in a web page.

I tried using the same approach as I used for Node.js (so using MQTT.js) but I'm unable to establish a connection with the broker as I'm getting a generic "Websocket connection failed" error message. The issue could likely be in my authentication using certificates. Here is the code I have tested:

<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/5.3.3/mqtt.js"></script>
<script language="javascript">
const keyValue = `-----BEGIN RSA PRIVATE KEY-----
ABC...
...
...XYZ
-----END RSA PRIVATE KEY-----`;

const certValue = `-----BEGIN CERTIFICATE-----
ABC...
...
...XYZ
-----END CERTIFICATE-----`;

const caValue = `-----BEGIN CERTIFICATE-----
ABC...
...
...XYZ
-----END CERTIFICATE-----`;

const options = {
    protocolVersion: 5,
    protocol: 'mqtts',
    host: 'XXXXXXXXXXXXXX-ats.iot.eu-central-1.amazonaws.com',
    port: 8883,
    ca: [caValue],
    cert: certValue,
    key: keyValue
};

console.log("Attempting to connect...");
const client = mqtt.connect(options);

client.on('connect', () => console.log("Connection established!"));
            
client.subscribe('party/window/ABCD');
client.on('message', function(topic, message) {
    console.log(`Received message on topic ${topic}: ${message}`);
});

client.on('disconnect', () => console.log('MQTT Connection lost'));
</script>

The error appears after the message "Attempting to connect". I have written key/cert/ca values explicitly here to get around issues in loading them from files (in Node.js I could simply use fs.readFileAsync for that).

Concluding, I have two questions:

  1. Why am I unable to connect to the broker with the code above?
  2. What would be a better way of handling this so that my key/cert/ca values are not exposed in code, as the ultimate goal would be to serve this solution on a public web page?

Solution

  • You can not use certificate based authentication from the browser.

    The browser javascript sandbox will only allow you to make use of certificates that are already in the browsers certificate store.

    You need to use the signed URL authentication method from the browser.

    Docs about options for authentication with AWS IoT Code

    https://docs.aws.amazon.com/iot/latest/developerguide/authorizing-direct-aws.html

    AWS provided example of how to connect from the browser

    https://github.com/aws-samples/aws-iot-wss-ts-client