question

Upvotes
Accepted
21 1 3 4

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:


authorisecontent.png


This is code that does the Hmac:


encodehmac.png


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.

#productworldcheck-one-apipostingcase
authorisecontent.png (356.7 KiB)
encodehmac.png (72.0 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Upvotes
Accepted
21 1 3 4

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.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

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;
Upvotes
546 4 0 2

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.


fsp-sdk-csharp.zip (10.9 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

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

refinitiv-csharp-page.pngNot 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.

refinitiv-csharp.png

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!


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": []
}


Upvote
546 4 0 2

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.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Thanks. Will find the best time when I am in the office tomorrow.
Could you send me an email and I will set up a meeting for 11 GMT. Thanks
Upvotes
1.3k 4 1 2

@rob.kent - I am marking this question as private as your API key im visible here.

icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

It is a test key but I would rather we masked the key rather than lose all that information.
Sure, marking it back to public
Thanks a lot!
Yes, so no information would be lost, marking it private basically means it will only be visible to us and yourself and not the other users on the dev portal.

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

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.