2

I am trying to make a request to the Amazon SP-API using PHP, but I keep getting an error that my request signature does not match. Although all of the values in my canonical request match up with what the API expected, my hashed value of the canonical request is different. Here is my code:

<?php

$host = 'sellingpartnerapi-na.amazon.com';
$service = 'execute-api';
$region = 'us-east-1';

$accessKey = "aws access key id";
$secretKey = 'aws secret access key';
$accessToken = 'lwa access token';

$requestUrl = 'https://sellingpartnerapi-na.amazon.com';
$httpRequestMethod = 'GET';
$terminationString = 'aws4_request';
$algorithm = 'AWS4-HMAC-SHA256';
$phpAlgorithm = 'sha256';
$signedHeaders = 'content-type;host;x-amz-access-token;x-amz-date';
$canonicalURI = '/';
$canonicalQueryString   = '';
$requestHasedPayload = hash($phpAlgorithm, '');

$currentDateTime = new DateTime('UTC');
$reqDate = $currentDateTime->format('Ymd');
$reqDateTime = $currentDateTime->format('Ymd\THis\Z');


// Create canonical request
$canonicalRequest = array();
$canonicalRequest[] = $httpRequestMethod;
$canonicalRequest[] = $canonicalURI;
$canonicalRequest[] = 'content-type:application/json';
$canonicalRequest[] = 'host:sellingpartnerapi-na.amazon.com';
$canonicalRequest[] = 'x-amz-access-token:' . $accessToken;
$canonicalRequest[] = 'x-amz-date:' . $reqDateTime . "\n";
$canonicalRequest[] = rawurlencode($signedHeaders);
$canonicalRequest[] = $canonicalQueryString;
$canonicalRequest[] = $requestHasedPayload;
$requestCanonicalRequest = implode("\n", $canonicalRequest);
$requestHasedCanonicalRequest = hash($phpAlgorithm, utf8_encode($requestCanonicalRequest));

// Create signing key
$kSecret = $secretKey;
$kDate = hash_hmac($phpAlgorithm, $reqDate, 'AWS4' . $kSecret, true);
$kRegion = hash_hmac($phpAlgorithm, $region, $kDate, true);
$kService = hash_hmac($phpAlgorithm, $service, $kRegion, true);
$kSigning = hash_hmac($phpAlgorithm, $terminationString, $kService, true);


// Create scope
$credentialScope = array();
$credentialScope[] = $reqDate;
$credentialScope[] = $region;
$credentialScope[] = $service;
$credentialScope[] = $terminationString;
$credentialScopeStr = implode('/', $credentialScope);

// Create string to sign
$stringToSign = array();
$stringToSign[] = $algorithm;
$stringToSign[] = $reqDateTime;
$stringToSign[] = $credentialScopeStr;
$stringToSign[] = $requestHasedCanonicalRequest;
$stringToSignStr = implode("\n", $stringToSign);


// Create signature
$signature = hash_hmac($phpAlgorithm, $stringToSignStr, $kSigning);

// Create authorization header
$authorizationHeader = array();
$authorizationHeader[] = 'Credential=' . $accessKey . '/' . $credentialScopeStr;
$authorizationHeader[] = 'SignedHeaders=' . $signedHeaders;
$authorizationHeader[] = 'Signature=' . ($signature);
$authorizationHeaderStr = $algorithm . ' ' . implode(', ', $authorizationHeader);


// Request headers
$headers = array();
$headers[] = 'authorization:'. $authorizationHeaderStr;
$headers[] = 'content-type: application/json';
$headers[] = 'host: ' . $host;
$headers[] = 'x-amz-date: ' . $reqDateTime;


$curl = curl_init();
curl_setopt_array($curl, array(
    CURLOPT_URL => $requestUrl,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_POST => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => $httpRequestMethod, 
    CURLOPT_VERBOSE => 0,
    CURLOPT_SSL_VERIFYHOST => 0,
    CURLOPT_SSL_VERIFYPEER => 0,
    CURLOPT_HEADER => false,
    CURLINFO_HEADER_OUT=>true,
    CURLOPT_HTTPHEADER => $headers,
));

$response = curl_exec($curl);
$err = curl_error($curl);
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);



curl_close($curl);

if ($err) {

        echo "<h5>Error:" . $responseCode . "</h5>";
        echo "<pre>";
        echo $err;
        echo "</pre>";

} else {

        echo "<h5>Response:" . $responseCode . "</h5>";
        echo "<pre>";
        echo $response;
        echo "</pre>";

}

And if you know a good resource for using the SP-API with php can you please share. The docs are very vague.

Thanks

dave_dev
  • 75
  • 6
  • did you ever figure this out? Having the same issue. canonical request matches amazon's exactly, but getting the error message that request signature doesn't match. Also trying to do this with php. – Kelli Sep 03 '22 at 15:17
  • I have similar issue. Things are working with postman but when try to use editor it doesn't return session token but error 'SignatureDoesNotMatch'. I used function as mentioned here at: https://stackoverflow.com/a/42816847/6760546 Any idea what can be wrong with code? PS: I'm trying to use service 'GetSessionToken' – Nilesh Apr 13 '23 at 17:53
  • I found right answer here: https://stackoverflow.com/questions/74514504/how-to-generate-aws-sp-api-signature-using-php/76022205#76022205 – Nilesh Apr 22 '23 at 04:43

1 Answers1

1

the documentation Signing AWS requests with Signature Version 4 has step by step method as well a well-defined python example for GET and POST Examples of the complete Signature Version 4 signing process (Python)

Here is another similar question being asked Signature Version 4 Signing Process in PHP to access API Gateway endpoint.

Please add some error information as well to your question helps people here to answer your question.

samtoddler
  • 8,463
  • 2
  • 26
  • 21
  • I followed the documentation recommendations. I even tried the python example. But the second I try to change it to use with the seller api it give the same error as php. The hashed conanical request does not match what was expected to receive despite the error showing that I have the same values in all of the conanical request fields. – dave_dev Jan 19 '21 at 19:24
  • I am not sure if you got time to look through [this](https://github.com/avi-wish/aws4-signature-php). check the clock on your system, been there many times. – samtoddler Jan 19 '21 at 19:32
  • I did see that. Thanks. But it did not resolve my error. – dave_dev Jan 19 '21 at 20:16
  • Check this @dave_dev https://stackoverflow.com/questions/74514504/how-to-generate-aws-sp-api-signature-using-php/76022205#76022205 – Nilesh Apr 22 '23 at 04:44