I've been trying to get the Log Collector API working in a node.js Azure Function but am stuck on the 403/Forbidden error which indicates I'm not forming the authorization header correctly. The complete code is in a github repository here:
https://github.com/sportsmgmt-labs/Azure-Log-Analytics-Node-Function
The Data Collector API documentation is here:
https://learn.microsoft.com/en-us/azure/log-analytics/log-analytics-data-collector-api
The authorization header should be formatted as follows:
Authorization: SharedKey {WorkspaceID}:{Signature}
Where the signature is encoded/encrypted like this:
Base64(HMAC-SHA256(UTF8(StringToSign)))
Here is my code that is creating the authorization header:
var contentLength = Buffer.byteLength(req.body['log-entry'], 'utf8');
var authorization = 'POST\n' + contentLength + '\napplication/json\nx-ms-date:' + processingDate + '\n/api/logs';
// encode string using Base64(HMAC-SHA256(UTF8(StringToSign)))
authorization = crypto.createHmac('sha256', sharedKey).update(authorization.toString('utf8')).digest('base64');
authorization = 'Authorization: SharedKey ' + workspaceId + ':' + authorization;
The response from the server is:
{"Error":"InvalidAuthorization","Message":"An invalid scheme was specified in the Authorization header"}
Could someone please help me understand what I'm doing wrong? Thanks!
Edit: Here is the Python code to do this:
def build_signature(customer_id, shared_key, date, content_length, method, content_type, resource):
x_headers = 'x-ms-date:' + date
string_to_hash = method + "\n" + str(content_length) + "\n" + content_type + "\n" + x_headers + "\n" + resource
bytes_to_hash = bytes(string_to_hash).encode('utf-8')
decoded_key = base64.b64decode(shared_key)
encoded_hash = base64.b64encode(hmac.new(decoded_key, bytes_to_hash, digestmod=hashlib.sha256).digest())
authorization = "SharedKey {}:{}".format(customer_id,encoded_hash)
return authorization
...and the C# code:
static void Main()
{
// Create a hash for the API signature
var datestring = DateTime.UtcNow.ToString("r");
string stringToHash = "POST\n" + json.Length + "\napplication/json\n" + "x-ms-date:" + datestring + "\n/api/logs";
string hashedString = BuildSignature(stringToHash, sharedKey);
string signature = "SharedKey " + customerId + ":" + hashedString;
PostData(signature, datestring, json);
}
// Build the API signature
public static string BuildSignature(string message, string secret)
{
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = Convert.FromBase64String(secret);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hash = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hash);
}
}