I am trying to generate a valid SAS token (shared access signatures) to connect to the Azure IoT Hub, but I keep getting the error Connection refused: Not authorized
when using the token.
I know the way I am connecting is working because when using a SAS token generated with the Microsoft Device Explorer (https://github.com/Azure/azure-iot-sdk-csharp/tree/master/tools/DeviceExplorer) it works as expected.
To write the Javascript code I started from this documentation https://learn.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1 comparing with some working implementations:
- in Python: https://github.com/Azure/azure-sdk-for-python/blob/master/azure-servicebus/azure/servicebus/servicebusservice.py
- in Go/Golang: https://github.com/openenergi/go-event-hub/blob/master/msauth/sasl.go
What am I doing wrong in the following Javascript implementation? I think it may be related to the SHA256 signature combined with URL escaping the string but I am not sure how to test/verify this.
const crypto = require('crypto');
// on the Azure Portal:
// sharedAccessKeyName is the "policy" field
// sharedAccessKeyValue is the "primary key"
const sign = (iotHubName, expirtyDeltaInSecondsFromNow, sharedAccessKeyName, sharedAccessKeyValue) => {
// URL encode the IoT Hub host
const encodedSasUrl = encodeURI(`${iotHubName}.azure-devices.net`.toLowerCase());
// calculate the expiry end datetime as an epoch
const expiry = parseInt(Date.now() / 1000 + expirtyDeltaInSecondsFromNow);
// combine the previous two pieces of information
const stringToSign = `${encodedSasUrl}\n${expiry}`;
// sign the string using the primary key (sharedAccessKeyValue) and SHA256
const hmac = crypto.createHmac('sha256', sharedAccessKeyValue);
hmac.update(stringToSign);
const hash = hmac.digest('hex');
// encode the signed hash to base64 (making sure it's URL escaped)
const encodedSignature = hash.toString('base64');
// put all together into the SAS token
const sasToken = `SharedAccessSignature sig=${encodedSignature}&se=${expiry}&skn=${sharedAccessKeyName}&sr=${encodedSasUrl}`;
console.log("sasToken:", sasToken);
return sasToken;
}