I can call any GET method on the Refinitiv World Check API and everything is signed and works okay but when I try to POST a Case, I get a 401 error. It works fine from Postman using my key and secret but my C# code doesn't. I have tried replacing the JSON content just with "{}" but it seems to be the authorisation failing before the server tries to process my message. This my code that creates the authorisation:
This is code that does the Hmac:
The GET and POST methods are identical and use common code apart from when set the content elements of the data to sign and obviously when we set the request message content.
Here is my actual code for the POST which uses the GET signature first then adds its own parms:
var byteLength = new UTF8Encoding().GetBytes(jsonContent).Length; var dataToSign = MakeCommonSignedData(httpMethod, localPath, utcDate) + "\n" + $"content-type: {ContentTypeJson}\n" + $"content-length: {byteLength}\n" + jsonContent; var hmac = EncodeHmac256(dataToSign); return $"Signature keyId=\"{config.ApiKey}\",algorithm=\"hmac-sha256\",headers=\"(request-target) host date content-type content-length\",signature=\"{hmac}\"";
Here is the logged data to sign:
(request-target): post /v2/cases host: api-worldcheck.refinitiv.com date: Sat, 11 Mar 2023 16:14:09 GMT content-type: application/json content-length: 295 { "note": null, "groupId": "5jb8a2z6imev1h93zc1zzooof", "entityType": "INDIVIDUAL", "caseId": "49db5529-b50c-4459-b1d3-ab52558eec58", "name": "Rob Kent", "nameTransposition": false, "providerTypes": [ "WATCHLIST" ], "customFields": [], "secondaryFields": [] }
Signature keyId="XXXXXXXXXXXXXX",algorithm="hmac-sha256",headers="(request-target) host date content-type content-length",signature="gbSDLGSAtfK8+fdvi9i56UduGGARVMLXpgRg8DNLLrs="
Here is my code that calls the above and sends the message:
var utcNow = DateTime.UtcNow; var requestMessage = new HttpRequestMessage(new HttpMethod(httpMethod), url); var jsonContent = jsonBody == null ? "" : JsonObjectBase.Serialize(jsonBody); //var jsonContent = httpMethod == httpGet ? null : "{}"; var authorisation = MakeAuthorisation(httpMethod, localPath, utcNow, jsonContent); requestMessage.Headers.Date = utcNow; requestMessage.Headers.Add("Authorization", authorisation); requestMessage.Headers.Add("Accept", ContentTypeJson); requestMessage.Headers.Add("Cache-Control", "no-cache"); if (jsonContent.HasValue()) { logger.Debug($"{httpMethod} JSON content:\r\n{jsonContent}"); requestMessage.Content = new StringContent(jsonContent, Encoding.UTF8, ContentTypeJson); } return await SendRequestAndParseResponseString(requestMessage);
Apparently the HttpClient creates the content-type and content-length headers automagically when you create the body content in that way.
I may have code-blindness from looking at it too long so if anyone can see anything wrong, I would be most grateful.