Skip to content

Instantly share code, notes, and snippets.

@RyanSept
Last active May 23, 2023 21:21
Show Gist options
  • Save RyanSept/d9f98a333c1a45d680e2d114c908e184 to your computer and use it in GitHub Desktop.
Save RyanSept/d9f98a333c1a45d680e2d114c908e184 to your computer and use it in GitHub Desktop.
Javascript AWS IoT MQTT WebSocket Client with AWS SigV4 Request Signing
// attribution: https://github.com/dwyl/learn-aws-iot/blob/46538441c4f6591eb23a7396d0a816ce8ff7806f/src/js/utils/request.js
var moment = require("moment");
var CryptoJS = require("crypto-js");
function SigV4Utils() {}
SigV4Utils.sign = function (key, msg) {
var hash = CryptoJS.HmacSHA256(msg, key);
return hash.toString(CryptoJS.enc.Hex);
};
SigV4Utils.sha256 = function (msg) {
var hash = CryptoJS.SHA256(msg);
return hash.toString(CryptoJS.enc.Hex);
};
SigV4Utils.getSignatureKey = function (
key,
dateStamp,
regionName,
serviceName
) {
var kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key);
var kRegion = CryptoJS.HmacSHA256(regionName, kDate);
var kService = CryptoJS.HmacSHA256(serviceName, kRegion);
var kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
return kSigning;
};
function formatRequestUrl(options) {
var time = moment.utc();
var dateStamp = time.format("YYYYMMDD");
var amzdate = dateStamp + "T" + time.format("HHmmss") + "Z";
var service = "iotdevicegateway";
var region = options.regionName;
var secretKey = options.secretKey;
var accessKey = options.accessKey;
var algorithm = "AWS4-HMAC-SHA256";
var method = "GET";
var canonicalUri = "/mqtt";
var host = options.endpoint;
var credentialScope =
dateStamp + "/" + region + "/" + service + "/" + "aws4_request";
var canonicalQuerystring = "X-Amz-Algorithm=AWS4-HMAC-SHA256";
canonicalQuerystring +=
"&X-Amz-Credential=" +
encodeURIComponent(accessKey + "/" + credentialScope);
canonicalQuerystring += "&X-Amz-Date=" + amzdate;
canonicalQuerystring += "&X-Amz-SignedHeaders=host";
var canonicalHeaders = "host:" + host + "\n";
var payloadHash = SigV4Utils.sha256("");
var canonicalRequest =
method +
"\n" +
canonicalUri +
"\n" +
canonicalQuerystring +
"\n" +
canonicalHeaders +
"\nhost\n" +
payloadHash;
console.log("canonicalRequest " + canonicalRequest);
var stringToSign =
algorithm +
"\n" +
amzdate +
"\n" +
credentialScope +
"\n" +
SigV4Utils.sha256(canonicalRequest);
var signingKey = SigV4Utils.getSignatureKey(
secretKey,
dateStamp,
region,
service
);
var signature = SigV4Utils.sign(signingKey, stringToSign);
canonicalQuerystring += "&X-Amz-Signature=" + signature;
var sessionToken = options.sessionToken
? "&X-Amz-Security-Token=" + options.sessionToken
: "";
return (
"wss://" + host + canonicalUri + "?" + canonicalQuerystring + sessionToken
);
}
const mqtt = require("mqtt");
// insert formatRequestUrl() result here:
const client = mqtt.connect(
formatRequestUrl({
regionName: "us-west-2",
secretKey: "feedme",
accessKey: "feedme",
endpoint: "feedme",
})
);
client.on("connect", function () {
console.log("CONN_ESTABLISHED");
client.subscribe(
"$aws/things/my-device/shadow/name/Status/get/accepted",
function (err) {
if (!err) {
console.log("SUBSCR_ESTABLISHED", err);
client.publish("$aws/things/my-device/shadow/name/Status/get", "");
}
}
);
});
client.on("message", function (topic, message) {
console.log("MSG_RCVD", message);
// message is Buffer
console.log(topic, message.toString());
});
{
"dependencies": {
"crypto-js": "^4.1.1",
"moment": "^2.29.4",
"mqtt": "^4.3.7"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment