aws / aws-sdk-php

Official repository of the AWS SDK for PHP (@awsforphp)
http://aws.amazon.com/sdkforphp
Apache License 2.0
6.03k stars 1.22k forks source link

InvalidSignatureException with signed request to Selling Partner API #2158

Closed winterstefan closed 3 years ago

winterstefan commented 3 years ago

Hi there,

my current use-case is to create an Amazon Application which accesses seller information (like inventory reports) via the newly launched Selling Partner API. For that, I'm using a PHP backend and try signing the SP-API requests with this AWS SDK. Indeed I'm aware that this repository neither supports topics for SP-API, Amazon Application development and such. But I'm at a very point, where signing a random request via the SDK fails. So now I'm humbly searching for help here since no other party was able to assist.

If I'm purely wrong here please accept my apology.

What I've done before opening this ticket

All that without a proper solution, unfortunately.

My setup
My use-case
My problem
Request

Here's the PHP code using the AWS SDK 'by hand' for signing the request. See this documentation for which params need to be in place for the SP-API request.

$options = [
            'host' => 'sandbox.sellingpartnerapi-eu.amazon.com',
            'region' => 'eu-west-1',
            'service' => 'execute-api',
            // @see https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md#step-1-create-an-aws-account
            'aws_user_key' => 'XXXX',
            // @see https://console.aws.amazon.com/iam/home?#/users/{user}
            'aws_user_secret' => 'XXXX',
            // @see https://github.com/amzn/selling-partner-api-docs/blob/main/guides/developer-guide/SellingPartnerApiDeveloperGuide.md#viewing-your-developer-information
            // @see https://sellercentral.amazon.com/sellingpartner/developerconsole/
            'seller_access_token' => 'Atza|IwXXXX',
        ];

        $credentials = new Credentials($options['aws_user_key'], $options['aws_user_secret']);
        $signatureV4 = new SignatureV4($options['service'], $options['region']);
        $url = 'https://sandbox.sellingpartnerapi-eu.amazon.com/reports/2020-09-04/reports';

        $request = new Request(
            'POST',
            $url,
            [
                'x-amz-access-token' => $options['seller_access_token'],
                'user-agent' => 'XXXX/0.0.1',
            ],
        );

        $request = $signatureV4->signRequest($request, $credentials);
        $client = new Client();

        $requestOptions = [
            'Host' => 'https://sellingpartnerapi-eu.amazon.com',
            'json' => [
                'reportType' => 'GET_MERCHANT_LISTINGS_ALL_DATA',
                "dataStartTime" => "2020-12-01T20:11:24.000Z",
                'marketplaceIds' => ['A1PA6795UKMFR9'], // German Marketplace
            ],
        ];

The actual request data:

URI: https://sandbox.sellingpartnerapi-eu.amazon.com/reports/2020-09-04/reports
Content-Type: application/x-www-form-urlencoded
Host: sandbox.sellingpartnerapi-eu.amazon.com
x-amz-access-token: Atza|IwXXXX
user-agent: XXXX/0.0.1
X-Amz-Date: 20201203T142037Z
Authorization: AWS4-HMAC-SHA256 Credential=AKIAXXXX2/20201203/eu-west-1/execute-api/aws4_request, SignedHeaders=host;x-amz-access-token;x-amz-date, Signature=4b49fdf54ba871f6864e57182a55eaa07b73d1XXXX
Response
Date: Thu, 03 Dec 2020 14:20:37 GMT
Content-Type: application/json
Content-Length: 1065
Connection: keep-alive
x-amzn-RequestId: 7ed7be70-e4a2-41cf-a99d-86611b585b9c
x-amzn-ErrorType: InvalidSignatureException
x-amz-apigw-id: W-sYcGzJjoEFkvQ=

string(1065) "{
  "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
/reports/2020-09-04/reports

host:sandbox.sellingpartnerapi-eu.amazon.com
x-amz-access-token:Atza|IwXXXX
x-amz-date:20201203T142037Z

host;x-amz-access-token;x-amz-date
4a0da4ea0d7492c7c0deba7e497f1cb3bXXXX'

The String-to-Sign should have been
'AWS4-HMAC-SHA256
20201203T142037Z
20201203/eu-west-1/execute-api/aws4_request
d452c541007be49898d8f92f187b655c4XXXX'
",
     "code": "InvalidSignature"
    }
  ]
}"

Any help or hint is appreciated. Reading Check your AWS Secret Access Key and signing method. I double checked the keys, so would leave just the signing method open. I tried to send and omit lots of request params (like the Accept and Content Type headers), since I've read this could influence the signing process. But right now I'm out of ideas, to be honest.

SamRemis commented 3 years ago

Hi @winterstefan, Within the signRequest method, we remove certain headers from the request headers before we sign, so that shouldn't be the issue. Did it work when you tried presigning the request instead? Or have you tried another using the CLI or another SDK and seen the same results?

winterstefan commented 3 years ago

Hello @SamRemis,

thank you for reaching out. Glad to hear, that additional headers should not be a problem. What do you mean by presigning the request?

At first, I tried to follow the SP-API guidelines for signing a request by hand. But with that, I didn't come anywhere near a successfully created signature.

So after some research, I stumbled upon the idea of using the AWS part to create the signature. I double-checked the source code, that actually creates the signature and it looked like the description I linked from documentation. So by that point, I relied on the AWS SDK.

Do you know some other SDK that implements the process?

winterstefan commented 3 years ago

Soo, after debugging day after day, I finally got the missing part. So thanks @SamRemis for reaching out initially, I'll close this issue and leave a quick note for others who might run into that problem.

In order to have the signature being valid, I need to assume the API role via AWS SDK thus getting actual credentials back. That was not mentioned in the docs I've read on the Selling Partner API. A kind person created a functional PHP example over here (link to the assumeRole call).


Thanks guys & stay save

github-actions[bot] commented 3 years ago

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

SamRemis commented 3 years ago

@winterstefan thank you so much for following up and posting the solution, and I apologize for not being able to get it to you faster. I have been in contact with the selling partner team, and will ask them to update their docs so that other customers don't experience this issue.

winterstefan commented 3 years ago

Awesome, thanks for reaching out to the SP team. 👍

Shahzeb42Digital commented 2 years ago

@SamRemis I am having same problem. I am using python package request for the authentication and signing in but, I have same error message. @winterstefan can please provide some additional information for example what is not mentioned in the documentation and what is missing because I could not understand PHP. Can you please give me detailed answer? Thanks!!