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

Signature does not match. #1554

Closed DomoES closed 3 years ago

DomoES commented 3 years ago

Error :

{
  "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
'GET
/sellers/v1/marketplaceParticipations/

host:sellingpartnerapi-na.amazon.com
user-agent:Domo Connector (Java)
x-amz-access-token:Atza|IwEBIP--EXAMPLE
x-amz-date:20210630T141236Z

host;user-agent;x-amz-access-token;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210630T141236Z
20210630/us-east-1/execute-api/aws4_request
74cb93efcdf17f349762115cf4819f7f756c3263c88ae99b829fedee9153e6ae'
",
     "code": "InvalidSignature"
    }
  ]
}

I have verified that my Canonical String and String-To-Sign are identical to these (include the case). So my issue must be in the Secret Access Key or Signing Method.

I went ahead and regenerated the access key and I am using the Java Example to get the Signature Key -> https://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-java

String-to-Sign and SignatureKey are then HmacSHA256'd together and hexEncoded to lower case.

Thus my final call ends up being :

GET /sellers/v1/marketplaceParticipations/ HTTP/1.1
Authorization: AWS4-HMAC-SHA256 Credential=AKI-EXAMPLE/20210630/us-east-1/execute-api/aws4_request, SignedHeaders=host;user-agent;x-amz-access-token;x-amz-date, Signature=f80bd966f88aa77c110-EXAMPLE
host: sellingpartnerapi-na.amazon.com
user-agent: Domo Connector (Java)
x-amz-access-token: Atza|IwEBI-EXAMPLE
x-amz-date: 20210630T135302Z

Which looks exactly like what you find in their example here -> https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#step-4-create-and-sign-your-request

I've gone over the other issues reported and they haven't fixed my problem : https://github.com/amzn/selling-partner-api-models/issues/1272 (capitalization of query parameter)' https://github.com/amzn/selling-partner-api-models/issues/1154 (regenerated my keys) https://github.com/amzn/selling-partner-api-models/issues/1101 (no resolution) https://github.com/amzn/selling-partner-api-models/issues/1098 (no resolution) https://github.com/amzn/selling-partner-api-models/issues/774 (canonical_uri change, execute-api for service) https://github.com/amzn/selling-partner-api-models/issues/769 (content-type header and x-amz-content-sha256 header)

None of it worked.

So - anyone have some insight or idea as to what might be the issue?

DomoES commented 3 years ago

Welp - figured it out.....

For posterity's sake : when following the instructions in AWS to create a role and what not (https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#creating-and-configuring-iam-policies-and-entities) you can either put in the user ARN or the roleARN.

If you do the role you HAVE to get temp credentials via STS (https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#step-4-create-and-sign-your-request) and use those as your ID (creating the authorization Header) and Secret (creating the signature key).

Then at the very end when you make your API call pass in "X-Amz-Security-Token" as a header with the session token you got back from your STS call.

phpandrew commented 3 years ago

Welp - figured it out.....

For posterity's sake : when following the instructions in AWS to create a role and what not (https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#creating-and-configuring-iam-policies-and-entities) you can either put in the user ARN or the roleARN.

If you do the role you HAVE to get temp credentials via STS (https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/developer-guide/SellingPartnerApiDeveloperGuide.md#step-4-create-and-sign-your-request) and use those as your ID (creating the authorization Header) and Secret (creating the signature key).

Then at the very end when you make your API call pass in "X-Amz-Security-Token" as a header with the session token you got back from your STS call.

Is there a specific API to call to get temp credentials via https://sts.amazonaws.com ?

DomoES commented 3 years ago

@phpandrew By default, AWS Security Token Service (AWS STS) is available as a global service, and all AWS STS requests go to a single endpoint at https://sts.amazonaws.com https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html

I had found an example some where of doing it manually - but for whatever reason couldn't get it to work. So I ended up using Amazon's SDK "com.amazonaws:aws-java-sdk-sts:1.11.+" (JAVA)

   BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(
                "Key from the role you made in IAM",
                "Secret from the role you made in IAM"
        );

        AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
                .withCredentials(new AWSStaticCredentialsProvider(basicAWSCredentials))
                .withRegion("REGION")
                .build();

        AssumeRoleRequest roleRequest = new AssumeRoleRequest()
                .withRoleArn("ARN to your Selling Partner account you made")
                .withDurationSeconds(DURATION)
                .withRoleSessionName("SESSION NAME");

        AssumeRoleResult roleResult = stsClient.assumeRole(roleRequest);
        stsGeneratedId = roleResult.getCredentials().getAccessKeyId();
        stsGeneratedSecret = roleResult.getCredentials().getSecretAccessKey();
        stsGeneratedSessionToken = roleResult.getCredentials().getSessionToken();

You use the stsGeneratedSecret when you create the signature in Task 3(https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html) and the stsGeneratedId when you create the authorization header in Task 4(https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html).

Then take the stsGeneratedSessionToken and use it in your API call with the "X-Amz-Security-Token" header. I didn't have to add this in the canonical parts or the signature or anything. I just tacked it on right before I made the api call.