amzon SP-API, SignatureDoesNotMatch

40 views Asked by At

I migrated from AWS to SP-API without any problems. I only habe a problem with uploading a feed. I try it since weeks in dozen ways. With httpPutRequest and GuzzleHttp\Client, with JSON and XML, with different headers, but I ever get the same error: Header: SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your key and signing method. I read that most the Content-Type is the problem, and I checked and changed it again and again... My actual code:

function sendFeed($feedURL) {
    $method = 'PUT';
    //$url = '\SellingPartnerApi\Model\FeedsV20210630\CreateFeedResponse'; 
    $url = $feedURL;
    
    $post2 ="{
    <?xml version='1.0' encoding='utf-8' ?>
    <AmazonEnvelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='amzn-envelope.xsd'>
      <Header>
      <DocumentVersion>1.01</DocumentVersion>
      <MerchantIdentifier>xxx</MerchantIdentifier>
      </Header>
      <MessageType>Inventory</MessageType>
      <Message>
        <MessageID>1</MessageID>
        <OperationType>Update</OperationType>
        <Inventory>
            <SKU>57832575-1</SKU>
            <Quantity>1</Quantity>
        </Inventory>
      </Message>
    </AmazonEnvelope> 
    }";
    $egal =  amazonSendFeedRequest($method, $url, $post2);
}

function amazonSendFeedRequest($method, $path, $post) {
     // Get access token
    $accessToken = getAccessToken();
    
    // Two formats for date used throughout
    $date = gmdate('Ymd\THis\Z');
    $ymd = gmdate('Ymd');
    
    // Build a canonical request. This is just a highly-structured and
    // ordered version of the request you will be making. Each part is
    // newline-separated. The number of headers is variable, but this
    // uses four headers. Headers must be in alphabetical order.
    $canonicalRequest = $method . "\n" // HTTP method
    . $path . "\n" //  Path component of the URL
    . $qs . "\n" // Query string component of the URL (without '?')
    . 'host:' . HOST . "\n" // Header
    . 'user-agent:' . USER_AGENT . "\n" // Header
    . 'x-amz-access-token:' . $accessToken . "\n" // Header
    . 'x-amz-date:' . $date . "\n" // Header
    . "\n" // A newline is needed here after the headers
    . 'host;user-agent;x-amz-access-token;x-amz-date' . "\n" // Header names
    . hash('sha256', $post); // Hash of the payload (empty string okay)
    
    // Create signing key, which is hashed four times, each time adding
    // more data to the key. Don't ask me why Amazon does it this way.
    $signKey = hash_hmac('sha256', $ymd, 'AWS4' . IAM_USER_SECRET, true);
    $signKey = hash_hmac('sha256', REGION, $signKey, true);
    $signKey = hash_hmac('sha256', 'execute-api', $signKey, true);
    $signKey = hash_hmac('sha256', 'aws4_request', $signKey, true);
    
    // Create a String-to-Sign, which indicates the hash that is used and
    // some data about the request, including the canonical request from above.
    $stringToSign = 'AWS4-HMAC-SHA256' . "\n"
    . $date . "\n"
    . $ymd . '/' . REGION . '/execute-api/aws4_request' . "\n"
    . hash('sha256', $canonicalRequest);
    
    // Sign the string with the key, which will create the signature
    // you'll need for the authorization header.
    $signature = hash_hmac('sha256', $stringToSign, $signKey);
    
    // Create Authorization header, which is the final step. It does NOT use
    // newlines to separate the data; it is all one line, just broken up here
    // for easier reading.
    $authorization = 'AWS4-HMAC-SHA256 '
    . 'Credential=' . IAM_USER_KEY . '/' . $ymd . '/'
     . REGION . '/execute-api/aws4_request,'
    . 'SignedHeaders=host;user-agent;x-amz-access-token;x-amz-date,'
    . 'Signature=' . $signature;   

    $headers = [];
    //$headers[] = 'authorization:' . $authorization;
    $headers[] = 'contentType:text/xml; charset=UTF-8';
    //$headers[] = 'host:' . HOST;
    //$headers[] = 'user-agent:' . USER_AGENT;
    //$headers[] = 'x-amz-access-token:' . $accessToken;
    //$headers[] = 'x-amz-date:' . $date;
    
    // Run the http request and capture the status code
    $status = '';
    $result = httpPutRequest($path, $post, $headers, $status);  

    // Validate the response
    if (strpos($result, 'Error:') === 0) exit($result);
    if (empty($result)) exit('Error: Empty response');
    if ($status != 200 AND $status != 201) exit('Error: Status code ' . $status . ': ' . $result);
    if (strpos($result, '{') !== 0) exit('Error: Invalid JSON: ' . $result);
    
    // Decode json and return it
    $json = json_decode($result, true);

    if (!$json) exit('Error: Problem decoding JSON: ' . $result);
    return $json;
}

I would be great if anyone can help me.

With httpPutRequest and GuzzleHttp\Client, with JSON and XML, with different headers

0

There are 0 answers