Amazon Seller Central MWS ListOrders GET request fails with "The request signature we calculated does not match the signature you provided." - signature

I'm trying to make a GET call to pull orders from Amazon, but I keep getting the same signature error. I've googled around and I see that a lot of people appear to have this error, but none of their solutions seem to fix my issue. Any thoughts?
My request code:
$MWS_Timestamp=GetUTCFormattedDateTime(Date(Now_()),'UTC',false); // 2018-10-22T13:51:32Z
$MWS_AccessKey='AKIA****************';
$MWS_ClientSecret='ChOqu*************************';
$MWS_DeveloperID=798*********;
$MWS_SellerID='A3DL**********';
$MWS_MarketPlaceID='ATVP*********';
$MWS_AuthToken='amzn.mws.********-****-****-****-************';
$MWS_Action='ListOrders';
$MWS_RequestString="";
$MWS_RequestString+="AWSAccessKeyId="+UrlEncode($MWS_AccessKey,0);
$MWS_RequestString+="&Action="+UrlEncode("ListOrders",0);
$MWS_RequestString+="&LastUpdatedAfter="+UrlEncode('2018-10-21T00:00:00Z',0);
$MWS_RequestString+="&MarketplaceId.Id.1="+UrlEncode($MWS_MarketPlaceID,0);
$MWS_RequestString+="&SellerId="+UrlEncode($MWS_SellerID,0);
$MWS_RequestString+="&SignatureVersion="+UrlEncode("2",0);
$MWS_RequestString+="&SignatureMethod="+UrlEncode("HmacSHA1",0);
$MWS_RequestString+="&Timestamp="+UrlEncode($MWS_Timestamp,0);
$MWS_RequestString+="&Version=2013-09-01";
$MWS_SignatureString=$MWS_RequestString;
$signature='';
/* Creating signature with CryptoJS
var hmacsha1Data=CryptoJS.HmacSHA1($MWS_SignatureString,$MWS_ClientSecret); //Also tried $MWS_AccessKey with the same results
var base64EncodeData=CryptoJS.enc.Base64.stringify(hmacsha1Data);
$signature=encodeURIComponent(base64EncodeData);
*/
RunScript("<TAG>Scripts/JS-CryptoJS_v3.12</TAG>");
$signature=Replace($signature,"+","%2B");
$signature=Replace($signature,"/","%2F");
$signature=Replace($signature,"=","%3D");
$MWS_Request=$MWS_RequestString+"&Signature="+$signature;
$MWS_URL='https://mws.amazonservices.com/Orders/2013-09-01?'+$MWS_Request;
The Response:
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<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.
</Message>
</Error>
<RequestID>54d6059b-9aa8-4d4f-a0b8-beb663599b25</RequestID>
</ErrorResponse>
I'm at a loss here as to which part is wrong. I double-checked the credentials, but everything looks good.

These parameters must all be appended in lexical order.
Here is one example where that isn't the case.
$MWS_RequestString+="&SellerId="+UrlEncode($MWS_SellerID,0);
$MWS_RequestString+="&LastUpdatedAfter="+UrlEncode('2018-10-21T00:00:00Z',0);
The order in the actual URL doesn't matter, but if you don't build them in this order then you won't calculate the right signature -- because the service will sort them before calculating the signature it expects you to send.
Also, your signature encoding is wrong.
$signature=Replace($signature,"+","%20")
There should be only 3 possibilities other than A-Z a-z 0-9:
+ becomes %2B
/ becomes %2F
= becomes %3D

Related

Openai Context related questions consultation

I can return the dialogue information normally through openai's text-davinci-003, but the context correlation function cannot be realized at present.
I searched and found that there is a "conversation_id" parameter, but after adding the parameter, the API returns "Unrecognized request argument supplied: conversation_id".
I would like to inquire if this feature requires paying users to use it. I am currently a free test user.
I searched and found that there is a "conversation_id" parameter, but after adding the parameter, the API returns "Unrecognized request argument supplied: conversation_id".
As is mentioned in the comments, conversation_id is not a valid input parameter, you can see the valid parameters in the API reference: https://platform.openai.com/docs/api-reference/completions/create

How do I validate the Hmac using NodeJS?

I can successfully create an Hmac via NodeJS using the following code:
(slightly altered example from : https://nodejs.org/api/crypto.html#cryptocreatehmacalgorithm-key-options)
Crypto.createHmac('sha256', Crypto.randomBytes(16))
.update('I love cupcakes')
.digest('hex');
That results in a value like the following (hex-based string Hmac signature):
fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53
How do I use that signature to verify that the data was not altered? (using NodeJS, of course).
My Assumption
I'm assuming there is a method call where you supply the data and the signature and you get a boolean that tells you if the data was altered or not -- or something similar.
Another Solution?
Oh, wait, as I was writing that I started thinking...
Do I need to store the original random bytes I generated (Crypto.randomBytes(16)) and pass them to the receiver so they can just generate the HMac again and verify that the result is the same (fb2937ca821264812d511d68ae06a643915931375633173ba64af9425f2ffd53)?
If that is true that would be odd, because the parameter for Crypto.randomBytes(16) is named secret (in the official example)*. Seems like that needs to be kept secret??
Please let me know if there is a way to verify the signature on the receiving side & how I do that.
Official Documentation : A Bit Confusing
Here's the function as it is defined in the official docs:
crypto.createHmac(algorithm, key[, options])
In the function definition, you can see the second param is named key.
However, in the example they refer to it as secret
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
.update('I love cupcakes')
.digest('hex');
console.log(hash);
Just posting the answer so if anyone in future sees this they will be able to have the definitive answer.
As the commentor (Topaco) pointed out, the simple answer is that:
The receiver who want wants to validate the Hmac simply needs to use the same key value & data and apply it to the method and retrieve the hash value.
const secret = 'abcdefg';
const hash = crypto.createHmac('sha256', secret)
.update('I love cupcakes')
.digest('hex');
console.log(hash);
The original Hmac-creating party must provide three things for the verifying party:
data : (could be encrypted data from AES256, for example)
key : original key passed into the createHmac() method -- note: this item is called secret in the sample code by NodeJS (above).
hash :the (clearText) hash which the original creator generated when calling the createHmac() method.
With those three things the verifying party can now call the createHmac() method and determine if the hash they get matches the hash that the original hmac-creating party generated.
Doing this validates that the Data which was sent has not been corrupted or altered.
Additional Note On Key (secret)
I've come back after thinking about the Hmac a bit more.
It is required that both parties know the key (aka secret) but it does not mean that it should be exposed to others.
This must be kept secret (as the code implies) because if a nefarious type knew the value and could alter it, then they could also alter the data and generate a new key (secret) and pass it along as if the original creator sent it along (MITM - man in the middle attack).
So, the point here is that yes, both parties have to know the key (secret) value, but it should not be shared where it might be discovered by nefarious types.
Instead, it will have to be agreed upon or based upon a secret password, etc.

Can't seem to find the issue with the requestID parameter for the request header

I am trying to pull data from a REST API that uses a "similar standard to JSON RPC". The params I am passing look right according to the documentation here and here.
The error I am receiving is ...message:"Header missing request ID".... I am unsure what I am missing that would properly declare the requestID.
I have looked at the documentation provided via the API I am trying to pull data from but it's not very helpful considering it's all in PHP and cURL. I am trying to complete this task using python-requests.
getParams = {'method': 'getCustomers', 'params':{'where':'', 'limit': 2}, 'id': 'getCustomers'}
Result:
{"result":null,"error":{"code":102,"message":"Header missing request ID","data":[]},"id":null}
The return result should contain a list of All Customers and their attributes in JSON format.
Turns out there is nothing wrong with the code I am using. There is an issue with the API I am attempting to call.
In my situation, I was getting the same error back and was required to send a X-Request-ID header. I fixed it by adding the following to my headers:
headers = {
'X-Request-ID': str(uuid.uuid1()) # generate GUID based on host & time
...
Note that (for me) the GUID needed to be of a specific format (e.g. matching the Regex ^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$
taken from https://www.geeksforgeeks.org/how-to-validate-guid-globally-unique-identifier-using-regular-expression/). For example, it still gave the same error if I just sent "test".

GetMyFeesEstimate API Amazon vba

I have a problem getting a reasonable answer from Amazon. The problem is only with GetMyFeesEstimate. The other stuff like GetMyPriceForASIN works. I'm trying to get a response with VBA/Excel.
Example Code from Amazon:
https://mws.amazonservices.de/Products/2011-10-01?
FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=A1PA6795UKMFR9
&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=ASIN
&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=3828934897
&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true
&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0
&AWSAccessKeyId=XXXXXXXXXXXXX
&Action=GetMyFeesEstimate
&SellerId=XXXXXXXXXXXXXX
&SignatureMethod=HmacSHA256
&SignatureVersion=2
&Timestamp=2018-01-07T10%3A26%3A27Z&Version=2011-10-01&Signature=bJJJorhyeKwejuddJs6Z%2BVYZZmKtm0CG2GAXTrShyZM%3D
If I try to use this signed request with my data I get the following mistake:
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.
Can someone help me with this?
Here is the Documentation from Amazon.
You haven't shown code on how you are signing the request.
Since you already have been succesful for one API, can you check if you that the decimal values you are using are exactly the same in signing string and POST request?
Sometime excel stores values like 30.0 as 0.3E02 or something like that and this causes the signing string to be different from your post request.
I have used Amazon Scratchpad to create a POST and also to get a guidance on the signing string.
Please go to https://mws.amazonservices.com/scratchpad/index.html
Once you enter the details on the left and click on submit, you can see the Request details and the signing string. If you create the request exactly as specified there and sign exactly as specified there, you shouldnt have a singing issue.
Here is the sample for your request:
POST /Products/2011-10-01?AWSAccessKeyId=
&Action=GetMyFeesEstimate
&SellerId=XXXXXXXXXXXXXX
&SignatureVersion=2
&Timestamp=2018-06-12T04%3A19%3A55Z
&Version=2011-10-01
&Signature=vJLewLVH7FmUD8cpST8dD51GBUJkt6Aj9FADGLoCjNQ%3D
&SignatureMethod=HmacSHA256
&FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=A1PA6795UKMFR9
&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=ASIN
&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=3828934897
&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true
&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=EUR
&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0 HTTP/1.1
Host: mws.amazonservices.com
x-amazon-user-agent: AmazonJavascriptScratchpad/1.0 (Language=Javascript)
Content-Type: text/xml
Here is the string to sign.
Note that you have to put CHR(10) for a new line. Do not put VBCRLF in the string.
POST
mws.amazonservices.com
/Products/2011-10-01
AWSAccessKeyId=&Action=GetMyFeesEstimate&FeesEstimateRequestList.FeesEstimateRequest.1.IdType=ASIN&FeesEstimateRequestList.FeesEstimateRequest.1.IdValue=3828934897&FeesEstimateRequestList.FeesEstimateRequest.1.Identifier=request1&FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled=true&FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId=A1PA6795UKMFR9&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount=30.00&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode=EUR&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber=0&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount=3.99&FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode=EUR&SellerId=XXXXXXXXXXXXXX&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2018-06-12T04%3A19%3A55Z&Version=2011-10-01

signature error

This shows error "The request signature we calculated does not match the signature you provided. Check your AWS.
string url;
integer statuscode;
String date1=json.serialize(Datetime.now());
if(date1.contains('"')){
date1=date1.replace('"','');}
String algorithmName = 'HmacSHA256';
date1=date1.substring(0,(date1.length()-5));
date1=date1+'Z';
date1=EncodingUtil.UrlEncode(date1,'UTF-8');
String Action=EncodingUtil.UrlEncode('CreateTopic','UTF-8');
String AccessKey=EncodingUtil.UrlEncode('APIKEY','UTF-8'); // API key hide due to security resion but i check it work fine for SES
String Signaturemethod=EncodingUtil.UrlEncode('HmacSHA256','UTF-8');
string str= 'GET\nsns.us-east-1.amazonaws.com\n/\nAction='+Action+'&Name=Testtopics&AWSAccessKeyId='+AccessKey+'&Timestamp='+date1+'&SignatureVersion=2&SignatureMethod='+Signaturemethod;
Blob mac = Crypto.generateMac(algorithmName,Blob.valueOf(str),Blob.valueOf('SECURITYKEY')); //blob value of key used in signature
url='https://sns.us-east-1.amazonaws.com/?Action=CreateTopic&Name=Testtopics&AWSAccessKeyId=ACCESSKEY&Timestamp='+date1+'&SignatureVersion=2&SignatureMethod=HmacSHA256&Signature='+EncodingUtil.UrlEncode(EncodingUtil.base64Encode(mac),'UTF-8'); // final url
I don't have much Idea about the AWS but below is what I was able to find. can't test these things anywhere to figue out the problem.
A common cause of the error message below is not properly creating the string to sign, such as forgetting to URL encode characters such as the colon (:) and the forward slash (/) in Amazon S3 bucket names.
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<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.</Message>
</Error>
http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html
http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html
It looks like you might be missing a trailing single quote at the end of your url. See if that makes a difference.
url="https://sns.us-east-1.amazonaws.com/?Action=CreateTopic&Name=Testtopics&AWSAccessKeyId=ACCESSKEY&Timestamp='+date1+'&SignatureVersion=2&SignatureMethod=HmacSHA256&Signature='+EncodingUtil.UrlEncode(EncodingUtil.base64Encode(mac),'UTF-8')+"'";

Resources