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
612 stars 736 forks source link

InvalidSignatureException with tokenApi.createRestrictedDataToken #215

Closed Mike-the-one closed 6 months ago

Mike-the-one commented 2 years ago

I am able to call getOrder API to get a list of orders but I am unable to get RDT because I need to access buyerInfo and shipping address.

I have followed this sample code here:

https://github.com/amzn/selling-partner-api-models/blob/main/clients/sample-code/RestrictedDataTokenWorkflow.java

But I always get 403 error when I try to get the RDT. This is the code:

CreateRestrictedDataTokenRequest restrictedDataTokenRequest = new CreateRestrictedDataTokenRequest();
        restrictedDataTokenRequest.setTargetApplication("amzn1.sellerapps.app.target-application");

        // Add a resource list to the CreateRestrictedDataTokenRequest object.
        String resourcePath = "/orders/v0/orders";
        // Define the dataElements to indicate the type of Personally Identifiable
        // Information requested.
        // This parameter is required only when getting an RDT for use with the
        // getOrder, getOrders, or getOrderItems operation of the Orders API.

        final List<String> dataElements = Arrays.asList("buyerInfo", "shippingAddress");

        RestrictedResource resource = new RestrictedResource();
        resource.setMethod(RestrictedResource.MethodEnum.GET);
        resource.setPath(resourcePath);
        resource.setDataElements(dataElements);

        List<RestrictedResource> resourceList = Arrays.asList(resource);

        restrictedDataTokenRequest.setRestrictedResources(resourceList);

        TokensApi tokensApi = new TokensApi.Builder().awsAuthenticationCredentials(awsAuthenticationCredentials)
                .awsAuthenticationCredentialsProvider(awsAuthenticationCredentialsProvider)
                .lwaAuthorizationCredentials(lwaAuthorizationCredentials)
                .endpoint("https://sellingpartnerapi-na.amazon.com").build();
        try {
            // Exception when createRestrictedDataToken is called
            CreateRestrictedDataTokenResponse response = tokensApi
                    .createRestrictedDataToken(restrictedDataTokenRequest);
            String restrictedDataToken = response.getRestrictedDataToken();
            return restrictedDataToken;
        } catch (ApiException e) {
            System.out.println(e.getResponseHeaders()); // Capture the response headers when a exception is thrown.
            throw e;
        }

And this is the response header:

Content-Type=[application[/json]()], Content-Length=[1646], Connection=[keep-alive], x-amzn-RequestId=[24346030-3074-450d-9a35-10cf6acb2c1f], x-amzn-ErrorType=[InvalidSignatureException], x-amz-apigw-id=xxxxxxxxx], OkHttp-Sent-Millis=[1643895557395], OkHttp-Received-Millis=[1643895557462]}

awsAuthenticationCredentials, awsAuthenticationCredentialsProvider and lwaAuthorizationCredentials should be correct since I am able to call other endpoints (not restricted resources).

The code was generated using the following command:

java -jar ./swagger-codegen-cli-2.4.13.jar generate -i <model file> --model-package com.amazon.spapi.models.$model -l java -t ../clients/sellingpartner-api-aa-java/resources/swagger-codegen/templates/ -o out -c ./config.json

and config.json:

{
  "groupId": "com.amazon",
  "artifactId": "spapi",
  "artifactVersion": "1.1.0",
  "invokerPackage": "com.amazon.spapi.client",
  "apiPackage": "com.amazon.spapi.api",
  "useGzipFeature": true,
  "library": "okhttp-gson"
}

Here are the request header and body:

Request body:

{
   "targetApplication":"Target Application",
   "restrictedResources":[
      {
         "method":"GET",
         "path":"[/orders/v0/orders]()",
         "dataElements":[
            "buyerInfo",
            "shippingAddress"
         ]
      }
   ]
}

And headers: (* are the values I replaced)

Accept = application/json
Authorization = AWS4-HMAC-SHA256 Credential=********************/20220204/us-east-1/execute-api/aws4_request, SignedHeaders=accept;content-type;host;user-agent;x-amz-access-token;x-amz-date;x-amz-security-token, Signature=ea0d96571eef2558959beb43c4c062877e073bb4a9f8ab80b2c2443fd8c34f2c
Content-Type = application/json
Host = sellingpartnerapi-na.amazon.com
User-Agent = Swagger-Codegen/1.1.0/java
x-amz-access-token = *************
X-Amz-Date = 20220204T113050Z
X-Amz-Security-Token = ************

This is the response body (* are the values I replaced)


{
  "errors": [
    {
      "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.

The Canonical String for this request should have been
'POST
/tokens/2021-03-01/restrictedDataToken

accept:application/json
content-type:application/json; charset=utf-8
host:sellingpartnerapi-na.amazon.com
user-agent:Swagger-Codegen/1.1.0/java
x-amz-access-token:**************
x-amz-date:20220204T123510Z
x-amz-security-token:********

accept;content-type;host;user-agent;x-amz-access-token;x-amz-date;x-amz-security-token
********(I replaced)'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20220204T123510Z
20220204/us-east-1/execute-api/aws4_request
0fa************************************8e2c'
",
     "code": "InvalidSignature"
    }
  ]
}

The AppClient.java is generated by swagger cli, AWSSigV4Signer.java is from the latest one from repo https://github.com/amzn/selling-partner-api-models

AWS dependency version

compile group: 'com.amazonaws', name: 'aws-java-sdk-signer', version: '1.12.152'
compile group: 'com.amazonaws', name: 'aws-java-sdk-sts', version: '1.12.152'

I am able to call SellersAPI.getMarketplaceParticipations() and OrdersAPI.getOrders(), both of these are GET commands, so no request body, I wondering if I miss something that the signer does not include the body to sign?

Thanks!

franciscocha commented 2 years ago

@Mike-the-one From what I can tell everything looks the way it should. My only question is your request body not sure where you got the json for it but the path

"path":"[/orders/v0/orders]()",

Should really be: "path":"/orders/v0/orders",

The only other thing that I can think of is that your credentials have changed.

github-actions[bot] commented 6 months ago

This is a very old issue that is probably not getting as much attention as it deserves. We encourage you to check if this is still an issue after the latest release and if you find that this is still a problem, please feel free to open a new issue and make a reference to this one.

github-actions[bot] commented 6 months ago

closed for inactivity