amzn / selling-partner-api-models

This repository contains OpenAPI models for developers to use when developing software to call Selling Partner APIs.
Apache License 2.0
580 stars 730 forks source link

C# Invalid Signature #67

Closed vinczgorad closed 11 months ago

vinczgorad commented 3 years ago

I using the Amazon Seller Partner Api C# library to get order history. According to their documentation, it pretty straight forward if I have the required credentials. Here is my code to get response on their api

`string resource = "/orders/v0/orders"; RestClient restClient = new RestClient("https://sellingpartnerapi-eu.amazon.com"); IRestRequest restRequest = new RestRequest(resource, Method.GET); restRequest.AddParameter("MarketPlaceIds", "A21TJRUUN4KGV"); restRequest.AddParameter("createdAfter", "2021-02-12T11:21:04.000Z"); AWSAuthenticationCredentials awsAuthenticationCredentials = new AWSAuthenticationCredentials { AccessKeyId = accessKey, SecretKey = secretKey, Region = awsRegion, };

restRequest = new AWSSigV4Signer(awsAuthenticationCredentials) .Sign(restRequest, restClient.BaseUrl.Host); var response = restClient.Execute(restRequest);`

Here is the response "{\n \"errors\": [\n {\n \"message\": \"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been\n'GET\n/orders/v0/orders\nMarketPlaceIds=A21TJRUUN4KGV&createdAfter=2021-02-12T11%3A21%3A04.000Z\nhost:sellingpartnerapi-eu.amazon.com\nx-amz-date:20210225T100959Z\n\nhost;x-amz-date\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\n20210225T100959Z\n20210225/eu-west-1/execute-api/aws4_request\na5faf7f2c8c55e7a512bae9dda3b1c41c9a66f54632089dd1547c49251627969'\n\",\n \"code\": \"InvalidSignature\"\n }\n ]\n}"

If I use the same accesskey and secret-key in postman, I am able to receive a response.

Do I need to provide additional headers before the api call? I have tried setting the headers into a RestRequest, without using the AWSSigV4Signer, but I am getting the same error.

Please advice. Thank you.

paul1965-Germany commented 3 years ago

Hello, i had the same error! Parameter is "CreateAfter" not "createAfter". Greetings

xavierhd commented 3 years ago

The C# model implementation is incorrect and have a lot of flaws. Have you called STS for credentials? #41 Based on https://github.com/amzn/selling-partner-api-models/issues/31#issuecomment-732270044 you need to build your AWSAuthenticationCredentials using something like :

AWSAuthenticationCredentials awsCredentials;

AssumeRoleResponse response = null;
RegionEndpoint region = RegionEndpoint.GetBySystemName(authentication.region);
using (var STSClient = new AmazonSecurityTokenServiceClient(authentication.accessKeyId, authentication.secretKey, authentication.region))
{
    var req = new AssumeRoleRequest()
    {
        RoleArn = authentication.RoleARN,
        DurationSeconds = 950, //put anything you want here
        RoleSessionName = Guid.NewGuid().ToString()
    };
    response = STSClient.AssumeRoleAsync(req, new CancellationToken()).Result;
}
restRequest.AddHeader("x-amz-security-token", response.Credentials.SessionToken);
awsCredentials = new AWSAuthenticationCredentials
{
    AccessKeyId = response.Credentials.AccessKeyId,
    SecretKey = response.Credentials.SecretAccessKey,
    Region = authenticationCredentialsProvider.Region
};
jadanah commented 2 years ago

Here's a link to my repo which has all the amazon selling partner api client's with some usage samples built via nswag using httpclient vs. amazon's restsharp implementation.

https://github.com/jadanah/amazon-selling-partner-api-csharp-samples

KRLow commented 1 year ago

If you dive in the codes, the way of generating hashing for the body of the request will only take the first Parameter object with type = "RequestBody". Please find the image below the code segment of how the library generate the hashing.

image

Please do take note that using RestSharp .AddJsonBody(object) function will face similar issue. The workaround I am using currently is appending the serialized body parameter using the .AddParameter(string, string, string, ParameterType) method.

string requestPath = "/notifications/v1/destinations";

IRestRequest request = new RestRequest(requestPath, Method.POST)
                .AddParameter(string.Empty, JsonSerializer.Serialize(form), System.Net.Mime.MediaTypeNames.Application.Json, ParameterType.RequestBody);

LWAAuthorizationCredentials lwaCredentials = new LWAAuthorizationCredentials()
            {
                ClientId = "clientId",
                ClientSecret = "clientSecret",
                RefreshToken = "refreshtoken",
                Endpoint = new Uri("https://api.amazon.com/auth/o2/token"),
                Scopes = new List<string>() { ScopeConstants.ScopeNotificationsAPI }
            };

AWSAuthenticationCredentials awsAuthenticationCredentils = new AWSAuthenticationCredentials()
            {
                AccessKeyId = "accessKey",
                SecretKey = "secretAccessKey",
                Region = "region"
            };

request = new LWAAuthorizationSigner(lwaCredentials)
            .Sign(request);

request = new AWSSigV4Signer(awsAuthenticationCredentils)
            .Sign(request, "sandbox.sellingpartnerapi-na.amazon.com"));

return await _restClient.PostAsync<CreateDestinationResponseForm>(request);
hinavinayak commented 11 months ago

Amazon released a new Version of the C# SDK, that no longer requires the AWS Sigv4.