401 Authorization error only with POST method to World Check API

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.
Best Answer
-
This was a very obscure problem that was solved by the Refinitiv team who did a Teams session with me and spotted the issue after we captured the output in Fiddler.
The issue is that the Refinitiv C# sample uses the older HttpWebRequest class and I am using the HttpClient library. When you set the Content with HttpWebRequest, you do this:
WebReq.ContentType = "application/json";
WebReq.ContentLength = byte1.Length;
Stream newStream = WebReq.GetRequestStream();
newStream.Write(byte1, 0, byte1.Length);So you have set the ContentType explicitly.
With HttpClient, you do this:
requestMessage.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json);
This automagically produces a request header of:
Content-Type: application/json; charset=utf-8
This no longer matches what you put in your data to sign:
string dataToSign = "(request-target): post " + gatewayurl + "cases/screeningRequest\n" +
"host: " + gatewayhost + "\n" + // no https only the host name
"date: " + date + "\n" + // GMT date as a string
"content-type: " + "application/json" + "\n" +
"content-length: " + byte1.Length + "\n"+
postData;So to fix it you have to change your data to sign so that it matches the actual content header, as follows:
// The content-type line must match exactly what the HttpClient creates when you set the Content.
// This is different to the Refinitiv sample code which uses the old WebRequest not HttpClient.
$"content-type: application/json; charset=utf-8\n" +
$"content-length: {byteLength}\n" +
jsonContent;When your signed data matches exactly the specified headers, the authorization error should go away.
0
Answers
-
Hi @rob.kent.
I'm looking into your code for a possible cause of the error. I have also attached the sample code provided by World-Check for your reference - fsp-sdk-csharp.zip. Thank you.
Regards,
Ssneha Balasubramanian.
0 -
Thank you. I have looked at that sample code and it is pretty much the same as the sample I got from this page https://developers.refinitiv.com/en/api-catalog/customer-and-third-party-screening/world-check-one-api/downloads
Not sure why but the above link refers to an older URL but the C# code is pretty much the same. It is a shame you don't have a sample that uses the more modern HttpClient library rather than WebRequest.
I took your sample code to create my own and as far as I can see they are the same but I might be missing something.
If you can see anything different/wrong with my code, I would be interested to know.
Thanks for your help!
0 -
I captured the request using Fiddler:
Here is the raw request:
POST https://api-worldcheck.refinitiv.com/v2/cases HTTP/1.1
Date: Sun, 12 Mar 2023 12:29:12 GMT
Authorization: Signature keyId="XXXXXXXXXXXXX",algorithm="hmac-sha256",headers="(request-target) host date content-type content-length",signature="5cFUajFSdOgsAuMxdNJoIul84UihBuJdLv6GmMC6TNM="
Accept: application/json
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Host: api-worldcheck.refinitiv.com
Content-Length: 295
Connection: Keep-Alive
{
"note": null,
"groupId": "5jb8a2z6imev1h93zc1zzooof",
"entityType": "INDIVIDUAL",
"caseId": "e690b6c6-b962-4bd8-bda3-d7cb90f080d9",
"name": "Rob Kent",
"nameTransposition": false,
"providerTypes": [
"WATCHLIST"
],
"customFields": [],
"secondaryFields": []
}0 -
Hi @rob.kent.
Can you please send me a meeting invite tomorrow for a timeslot of your choice so we can connect regarding this? Thank you.
Regards,
Ssneha Balasubramanian.
0 -
0
-
0
-
@rob.kent - I am marking this question as private as your API key im visible here.
0 -
0
-
0
-
I have removed the ids so please leave it as public. It is important that others with the same problem can find the question and solution. Thanks
0 -
0
-
0
-
Although the above fix worked, I later started getting a 415 error. The documentation says:
"For requests with payloads, an unsupported Content-Type was specified. The World-Check One API only supports a content type of application/json."
I don't know why this suddenly started happening but you can override the content headers after setting the content like this:
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue(ContentTypeJson);
I then changed my signing code back to what it was originally:
$"content-type: {ContentTypeJson}\n" +
$"content-length: {byteLength}\n" +
jsonContent;0
Categories
- All Categories
- 6 AHS
- 36 Alpha
- 166 App Studio
- 6 Block Chain
- 4 Bot Platform
- 18 Connected Risk APIs
- 47 Data Fusion
- 34 Data Model Discovery
- 684 Datastream
- 1.4K DSS
- 613 Eikon COM
- 5.2K Eikon Data APIs
- 10 Electronic Trading
- Generic FIX
- 7 Local Bank Node API
- 3 Trading API
- 2.9K Elektron
- 1.4K EMA
- 248 ETA
- 552 WebSocket API
- 37 FX Venues
- 14 FX Market Data
- 1 FX Post Trade
- 1 FX Trading - Matching
- 12 FX Trading – RFQ Maker
- 5 Intelligent Tagging
- 2 Legal One
- 23 Messenger Bot
- 3 Messenger Side by Side
- 9 ONESOURCE
- 7 Indirect Tax
- 60 Open Calais
- 275 Open PermID
- 44 Entity Search
- 2 Org ID
- 1 PAM
- PAM - Logging
- 6 Product Insight
- Project Tracking
- ProView
- ProView Internal
- 22 RDMS
- 1.9K Refinitiv Data Platform
- 629 Refinitiv Data Platform Libraries
- 4 LSEG Due Diligence
- LSEG Due Diligence Portal API
- 4 Refinitiv Due Dilligence Centre
- Rose's Space
- 1.2K Screening
- 18 Qual-ID API
- 13 Screening Deployed
- 23 Screening Online
- 12 World-Check Customer Risk Screener
- 1K World-Check One
- 46 World-Check One Zero Footprint
- 45 Side by Side Integration API
- 2 Test Space
- 3 Thomson One Smart
- 10 TR Knowledge Graph
- 151 Transactions
- 143 REDI API
- 1.8K TREP APIs
- 4 CAT
- 26 DACS Station
- 121 Open DACS
- 1.1K RFA
- 104 UPA
- 191 TREP Infrastructure
- 228 TRKD
- 915 TRTH
- 5 Velocity Analytics
- 9 Wealth Management Web Services
- 86 Workspace SDK
- 11 Element Framework
- 5 Grid
- 18 World-Check Data File
- 1 Yield Book Analytics
- 46 中文论坛