AWS IoT Core / mqtt.js - After Successful Topic Subscription, Still Not Able To Run a Callback On a Message

0

I'm trying to use the mqtt.js (https://github.com/mqttjs/MQTT.js) library in order to interact with the AWS IoT Core endpoint with the following code:

const mqtt = require("mqtt");

const IOT_ENDPOINT = "wss://xxxxxx-ats.iot.eu-central-1.amazonaws.com";
const client = mqtt.connect(`${IOT_ENDPOINT}/mqtt?x-amz-customauthorizer-name=Authorizer`);

client.on("connect", () => {
    client.subscribe("xyz", err => {
        if (!err) {
            // Works, I can see the message in AWS Console / MQTT test client.
            const dt = new Date().toISOString();
            client.publish("xyz", JSON.stringify({ message: "CURRENT DT:" + dt }));
        }
    });
});

// The callback never gets executed, nothing is printed in the console.
client.on("message", (topic, message) => {
    console.log("Message received.");
    client.end();
});

What's interesting is that I can see the published message in the xyz topic in the AWS Console / MQTT test client. Great!

What I can also see is that there are no messages being printed in my terminal, despite the fact that the client.subscribe call did not throw any errors (in other words, topic subscription was successful), and I am able to publish messages on the same topic from the AWS Console / MQTT test client.

I've tried multiple things, changing params when connecting, trying different variations of the code, no luck 😩.

My next idea on how to debug is to try enabling IOT CW logs and see if anything is logged in there maybe.

Until then, my question is: anybody have any suggestions on what else to check why nothing is being printed in my terminal?

Thank you!🍻

UPDATE: Sharing my AWS Lambda authorizer code, maybe it's something related to permissions? 🤔

module.exports.handler = async (event, _, callback) => {
    return ({
        isAuthenticated: true,
        principalId: 'Unauthenticated',
        policyDocuments: [
            {
                "Version": "2012-10-17",
                "Statement": [
              
                    {
                        "Effect": "Allow",
                        "Action": "iot:Connect",
                        "Resource": "arn:aws:iot:*:*:client/*"
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Subscribe",
                        "Resource": [
                             // Added '*' for testing purposes.
                            '*',
          "arn:aws:iot:*:*:client/*",
                            "arn:aws:iot:*:*:topicfilter/server"
                            
                            
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Publish",
                        "Resource": [
                            "arn:aws:iot:*:*:client/*",
                            "arn:aws:iot:*:*:topic/xyz"
                        ]
                    }
                ]
            }
        ],
        disconnectAfterInSeconds: 3600,
        refreshAfterInSeconds: 300
    });
};
profile picture
Adrian
asked 25 days ago110 views
3 Answers
1
Accepted Answer

Hi Adrian,

in your code your subscribe to the topic xyz but your policy allows only to subscribe to the topic server. You don't need the client-resource in the publish or subscribe actions. You can find some sample IoT policies at https://docs.aws.amazon.com/iot/latest/developerguide/pub-sub-policy.html. Might be our blog about using standard MQTT libraries with AWS IoT Core can also provide some guidance for you.

Cheers,
Philipp

AWS
EXPERT
answered 24 days ago
profile picture
EXPERT
reviewed 24 days ago
1

It seems that your AWS Lambda authorizer configuration might be the source of the issue. Your authorizer is configured to allow the "iot:Subscribe" action on specific resources, including the topic "server", but it does not explicitly allow subscription to the "xyz" topic, which your client is subscribing to.

To fix this, you should add an explicit permission for subscribing to the "xyz" topic in your authorizer's policy document. Here's how you can modify your policy document:

{
    "Effect": "Allow",
    "Action": "iot:Subscribe",
    "Resource": [
        "*",
        "arn:aws:iot:*:*:client/*",
        "arn:aws:iot:*:*:topicfilter/server",
        "arn:aws:iot:*:*:topicfilter/xyz"  // Add this line to allow subscription to the "xyz" topic
    ]
}

After updating your authorizer's policy document, redeploy it and retry your MQTT client code. This should resolve the issue and allow your client to receive messages from the "xyz" topic.

profile picture
EXPERT
answered 24 days ago
0

Hey everybody, thanks for your answers and leading me to further inspect the permissions returned from the Lambda function authorizer.

Here's the policy I'm now returning and that finally works:

module.exports.handler = async (event, _, callback) => {
    return ({
        isAuthenticated: true,
        principalId: 'Unauthenticated',
        policyDocuments: [
            {
                "Version": "2012-10-17",
                "Statement": [

                    {
                        "Effect": "Allow",
                        "Action": "iot:Connect",
                        "Resource": "arn:aws:iot:*:*:client/*"
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Subscribe",
                        "Resource": [
                            "arn:aws:iot:*:*:topicfilter/xyz"
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iot:Publish",
                        "Resource": [
                            "arn:aws:iot:*:*:topic/xyz"
                        ]
                    },
                    {
                        "Effect": "Allow",
                        "Action": [
                            "iot:Receive"
                        ],
                        "Resource": [
                            "arn:aws:iot:*:*:topic/xyz"
                        ]
                    }
                ]
            }
        ],
        disconnectAfterInSeconds: 3600,
        refreshAfterInSeconds: 300
    });
};

The thing I was actually missing was the last iot:Receive action:

{
  "Effect": "Allow",
  "Action": [
    "iot:Receive"
  ],
  "Resource": [
    "arn:aws:iot:*:*:topic/xyz"
  ]
}

I saw this in the https://docs.aws.amazon.com/iot/latest/developerguide/pub-sub-policy.html article that Philipp shared. So I decided to mark his reply as the answer to my question. 😉

Thanks again guys for providing help!

Cheers! 🍻🍻

profile picture
Adrian
answered 24 days ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions