question

Upvotes
Accepted
1 0 0 0

Keep getting 401 error for world check one api

Hi there,

Currently I am trying to integrate your API to our system.

I keep getting the same error 401 from my code. Postman works though.

I use fillder to catch the request send by postman and visual studio. For the authorization part they looks exactly the same except the hashed part.

POST /v1/cases/screeningRequest HTTP/1.1
Date: Thu, 23 May 2019 17:30:21 GMT
Content-Type: application/json
Authorization: Signature keyId="x",algorithm="hmac-sha256",headers="(request-target) host date content-type content-length",signature="jMx3FJvGsR2A2Q23fk90ihCwou3u00LHFwejYoxa1+o="
Content-Length: 150
User-Agent: PostmanRuntime/7.13.0
Accept: */*
Cache-Control: no-cache
Postman-Token: 736fcfdd-3fd7-45d1-93fc-b74bdfb55552
Host: zfs-world-check-one-api-pilot.thomsonreuters.com
accept-encoding: gzip, deflate
Connection: close


POST /v1/cases/screeningRequest HTTP/1.1
Date: Thu, 23 May 2019 17:37:29 GMT
Authorization: Signature keyId="x",algorithm="hmac-sha256",headers="(request-target) host date content-type content-length",signature="6jslfdOjpdkwdjbc7CdjE1QMQig30Tmu4TFUmS3j/CE="
Accept: */*
Cache-Control: no-cache
Content-Type: application/json; charset=utf-8
Host: zfs-world-check-one-api-pilot.thomsonreuters.com
Content-Length: 150
Expect: 100-continue
Connection: Keep-Alive

I also tried to hard code the time to match the one send by postman, then I got exactly the same hashed value. So I suppose the hash function is ok as well?

If so, why I keep getting 401 error? Can you help me to take a look my code? Thanks

public async Task<WorldCheckOneClientResponse> VerifyAsync(WorldCheckOneClientRequest request, CancellationToken cancellationToken)
{
    var currentDate = DateTime.UtcNow;
    var requestToSent =
        "{\"groupId\":\"xxxxxxxxxxxxxxxx\",\"entityType\": \"INDIVIDUAL\",\"providerTypes\": [\"WATCHLIST\"],\"name\": \"john smith\",\"secondaryFields\":[]}";
    UTF8Encoding encoding = new UTF8Encoding();
    var contentLength = encoding.GetBytes(requestToSent).Length;


    using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, request.EndpointUrl))
    {
        using (var stringContent = new StringContent(requestToSent, Encoding.UTF8, "application/json"))
        {
            httpRequest.Headers.Date = currentDate;
            httpRequest.Content = stringContent;
            httpRequest.Headers.Add("Authorization", getAuthorizationHeader(getDataToSign(request.EndpointUrl, currentDate, contentLength), request.ApiSecret, request.ApiKey));
            httpRequest.Headers.Add("Accept","*/*");
            httpRequest.Headers.Add("Cache-Control", "no-cache");


            using (var response = await _httpClient.SendAsync(httpRequest, cancellationToken))
            {
                var clientResponse = await response.Content.ReadAsStringAsync();
                OnResponseReceived(clientResponse);


                if (response.IsSuccessStatusCode)
                {
                    return JsonConvert.DeserializeObject<WorldCheckOneClientResponse>(clientResponse);
                }
                return new WorldCheckOneClientResponse
                {
                    HasError = true,
                    ErrorCode = response.StatusCode,
                };
            }
        }
    }
}


private string getDataToSign(Uri endpointUri, DateTime dateTime, int contentLength)
{
    var dataToSign = "(request-target): post " + "/v1/" + "cases/screeningRequest\n" +
                     "host: " + endpointUri.Host + "\n" +
                     "date: " + dateTime.ToString("R") + "\n" +
                     "content-type: " + "application/json" +"\n" + 
                     "content-length: " + contentLength;
    return dataToSign;
}


private string getAuthorizationHeader(string message, string secret, string apiKey)
{
    secret = secret ?? "";
    var encoding = new System.Text.ASCIIEncoding();
    byte[] keyByte = encoding.GetBytes(secret);
    byte[] messageBytes = encoding.GetBytes(message);
    using (var hmacsha256 = new HMACSHA256(keyByte))
    {
        var hashmessage = hmacsha256.ComputeHash(messageBytes);
        var hmc = Convert.ToBase64String(hashmessage);
        var returnValue = "Signature keyId=\"" + apiKey + "\",algorithm=\"hmac-sha256\",headers=\"(request-target) host date content-type content-length\",signature=\"" +
                          hmc + "\"";
        return returnValue;
    }
}


world-checkworld-check-oneerror-401world-check-one-zf
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
4.2k 8 5 6

@gaurav.thakur

Request you to provide us the response headers (in the below format) that you are sending to ZFS server so that I can assist you.

Date:

Authorization:

content-type:

content-length:

Also, please provide us the dataToSign value that you are passing to HMAC function and the JSON payload being sent (in the correct format so that I can calculate the content length of it at my end).

Lastly, I would need the response headers we are sending after the sync screening API call is used.

As soon as I have the above information, I will further debug the reason for 401.

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.

@gaurav.thakur you can mask the API key when you provide us the requested information

@gaurav.thakur Following up to see if you were able to resolve the issue. If yes, kindly share with us, how were you able to fix the 401 error?

Hi Irfan, It was due to setting the Charset to "UTF-8" in the header.

Removing it resolved the problem.

@Irfan.Khan: The pilot environment has been working fine for us, however, we are now getting a 401 against our live credentials with the exact same request structure. Could you please look into it? I have sent you the details in an email. It could be a permission issue. Thanks!

Upvotes
1 0 0 0

Somehow the code was not post correctly

Here is the formatted one:


public async Task<WorldCheckOneClientResponse> VerifyAsync(WorldCheckOneClientRequest request, CancellationToken cancellationToken)
{
    var currentDate = DateTime.UtcNow;
    var requestToSent =
        "{\"groupId\":\"xxxxxxxxxxxxxxxx\",\"entityType\": \"INDIVIDUAL\",\"providerTypes\": [\"WATCHLIST\"],\"name\": \"john smith\",\"secondaryFields\":[]}";
    UTF8Encoding encoding = new UTF8Encoding();
    var contentLength = encoding.GetBytes(requestToSent).Length;


    using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, request.EndpointUrl))
    {
        using (var stringContent = new StringContent(requestToSent, Encoding.UTF8, "application/json"))
        {
            httpRequest.Headers.Date = currentDate;
            httpRequest.Content = stringContent;
            httpRequest.Headers.Add("Authorization", getAuthorizationHeader(getDataToSign(request.EndpointUrl, currentDate, contentLength), request.ApiSecret, request.ApiKey));
            httpRequest.Headers.Add("Accept","*/*");
            httpRequest.Headers.Add("Cache-Control", "no-cache");


            using (var response = await _httpClient.SendAsync(httpRequest, cancellationToken))
            {
                var clientResponse = await response.Content.ReadAsStringAsync();
                OnResponseReceived(clientResponse);


                if (response.IsSuccessStatusCode)
                {
                    return JsonConvert.DeserializeObject<WorldCheckOneClientResponse>(clientResponse);
                }
                return new WorldCheckOneClientResponse
                {
                    HasError = true,
                    ErrorCode = response.StatusCode,
                };
            }
        }
    }
}


private string getDataToSign(Uri endpointUri, DateTime dateTime, int contentLength)
{
    var dataToSign = "(request-target): post " + "/v1/" + "cases/screeningRequest\n" +
                     "host: " + endpointUri.Host + "\n" +
                     "date: " + dateTime.ToString("R") + "\n" +
                     "content-type: " + "application/json" +"\n" + 
                     "content-length: " + contentLength;
    return dataToSign;
}


private string getAuthorizationHeader(string message, string secret, string apiKey)
{
    secret = secret ?? "";
    var encoding = new System.Text.ASCIIEncoding();
    byte[] keyByte = encoding.GetBytes(secret);
    byte[] messageBytes = encoding.GetBytes(message);
    using (var hmacsha256 = new HMACSHA256(keyByte))
    {
        var hashmessage = hmacsha256.ComputeHash(messageBytes);
        var hmc = Convert.ToBase64String(hashmessage);
        var returnValue = "Signature keyId=\"" + apiKey + "\",algorithm=\"hmac-sha256\",headers=\"(request-target) host date content-type content-length\",signature=\"" +
                          hmc + "\"";
        return returnValue;
    }
}


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.

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.