Problems encoding Amazon Flexible Payments secret string in PHP
Asked Answered
N

7

7

I am trying to use Amazon Payment Services, and they require me to do something like this:

Here is the complete signature so you can see I added the signature method:

$string_to_sign = "GET\n
authorize.payments-sandbox.amazon.com\n
cobranded-ui/actions/start?
SignatureMethod=HmacSHA256&SignatureVersion=2&callerKey=my_key&callerReference=YourCallerReference&paymentReason=donation&pipelineName=SingleUse&returnUrl=http%3A%2F%2Fyourwebsite.com%2Freturn.html&transactionAmount=4.0";

and then I encrypt it like below.

$encoded_string_to_sign = URLEncode(Base64_Encode(hash_hmac("sha256", $string_to_sign, 'my_secret_key')));

I do that, but then I get an error from them saying:

Caller Input Exception: The following input(s) are either invalid or absent:[signatureMethod]

Any idea what might be going wrong here?

Here is the entire code for this: (the variables are assigned values above)

<?php
$string_to_sign = 'GET
authorize.payments-sandbox.amazon.com/cobranded-ui/actions/startSignatureMethod=HmacSHA256&SignatureVersion=2&callerKey=AKIAJENBYSJCJX2IDWDQ&callerReference=YourCallerReference&paymentReason=donation&pipelineName=SingleUse&returnUrl=http%3A%2F%2Fproblemio.com&transactionAmount=4.0';

    $encoded_string_to_sign = URLEncode(Base64_Encode(hash_hmac("sha256", $string_to_sign, 'my_secret_key')));

$amazon_request_sandbox = 'https://authorize.payments-sandbox.amazon.com/cobranded-ui/actions/start?SignatureVersion=2&returnUrl='.$return_url.'&paymentReason='.$payment_reason.'&callerReference=YourCallerReference&callerKey='.$my_access_key_id.'&transactionAmount=4.0&pipelineName=SingleUse&SignatureMethod=HmacSHA256&Signature='.$encoded_string_to_sign;

//echo $amazon_request_sandbox; - use this if you want to see the resulting request and paste it into the browser

header('Location: '.$amazon_request_sandbox);
?>

Thanks!!

Naturalist answered 13/1, 2012 at 20:17 Comment(6)
I edited my original Q to show that I am including the SignatureMethod=HmacSHA256 string, but it doesn't help :(Naturalist
Have you made sure that there is no white space creeping in to you query string say perhaps after "start?"?Stoddard
Can I also ask why you are encoding the : and / characters in your returnUrl if you are URLEncoding it anyway?Stoddard
Please provide all of the code used to generate your request. You haven't provided enough code for us to reproduce the issue. We won't be able to trouble shoot this issue without being able to reproduce it. The best answers you can expect are speculations based on the provided error code. As I have suggested to you in two of your previous questions related to FPS you need to be using the FPS library provided here aws.amazon.com/code/Amazon-FPS/4094948623747680 or at the very least you need to study the code as an example.Stoops
@JonathanSpooner just added all the code to generate the request. Thanks for trying to help :)Naturalist
@Stoddard I am not sure why I am encoding things that way - just following their example to do what I thought they wanted. :)Naturalist
F
5

Check if you included &SignatureMethod=HmacSHA256 on the request

This kind of errors has 3 basic natures:

  • Missing Keys/Values
  • Typos on Keys/Values
  • Incorrect encoding or spaces on Keys/Values

Hope that helps!

Regards

Facelifting answered 13/1, 2012 at 20:28 Comment(0)
S
3

The only piece that wasn't suggested was that you need to use rawurlencode() on the transactionAmount that's part of the $string_to_sign.

Most other answers are a piece of the problem. For instance, you need to add a new line to the $string_to_sign after the GET (which you have), after the authorize.payments-sandbox.amazon.com, and after the /cobranded-ui/actions/start. You also need to set the $raw_output parameter to true in the hash_hmac() function.

I've included a complete working rewrite of your code (replace <Your_Access_Key> and <Your_Secret_Key>):

$return_url = rawurlencode('http://problemio.com');
$payment_reason = 'donation';
$transaction_amount = rawurlencode('4.0');

$secret_key = '<Your_Secret_Key>';
$my_access_key_id = '<Your_Access_Key>';

$string_to_sign = 'GET
authorize.payments-sandbox.amazon.com
/cobranded-ui/actions/start
SignatureMethod=HmacSHA256&SignatureVersion=2&callerKey=' . $my_access_key_id . '&callerReference=YourCallerReference&paymentReason=' . $payment_reason . '&pipelineName=SingleUse&returnUrl=' . $return_url . '&transactionAmount=' . $transaction_amount;

$encoded_string_to_sign = URLEncode(Base64_Encode(hash_hmac("sha256", $string_to_sign, $secret_key, true)));

$amazon_request_sandbox = 'https://authorize.payments-sandbox.amazon.com/cobranded-ui/actions/start?SignatureVersion=2&returnUrl=' . $return_url . '&paymentReason=' . $payment_reason . '&callerReference=YourCallerReference&callerKey=' . $my_access_key_id . '&transactionAmount=4.0&pipelineName=SingleUse&SignatureMethod=HmacSHA256&Signature=' . $encoded_string_to_sign;

However, I strongly suggest that you use the PHP library provided by the FPS community which can be downloaded here. I use this in production code and have never had an issue. Using the FPS library, your code would look like the following:

<?php

require_once 'CBUISingleUsePipeline.php';
require_once 'CBUIPipeline.php';

$secret_key = '<Your_Secret_Key>';
$my_access_key_id = '<Your_Access_Key>';

$return_url = 'http://problemio.com';
$transaction_amount = '4.0';
$caller_reference = '<Your_Caller_Reference>';
$payment_reason = 'donation';

$base = 'https://authorize.payments-sandbox.amazon.com/cobranded-ui/actions/start';

$pipeline = new Amazon_FPS_CBUISingleUsePipeline($my_access_key_id, $secret_key);
$pipeline->setMandatoryParameters($caller_reference, $return_url, $transaction_amount);
$pipeline->addParameter('paymentReason', $payment_reason);
$uRL = $pipeline->getURL($base);

?>
Stoops answered 21/1, 2012 at 1:10 Comment(0)
S
2

Have you set your signature method? from the AWS documentation:

You must set the SignatureMethod request parameter to either HmacSHA256 or HmacSHA1 to indicate which signing method you're using

Shelleyshellfire answered 13/1, 2012 at 20:23 Comment(0)
S
2

I don't believe you need to base64 encode the hash (after all, it's already being urlencoded) -- try removing Base64_Encode.

Scandal answered 18/1, 2012 at 16:55 Comment(0)
S
2

Your $string_to_sign variable is missing a '?' between start and SignatureMethod for your encoded Signature.

Signature version 2 is an enhanced signing method for both Amazon Simple Pay and Amazon Flexible Payments Service.

For inbound requests (from your application to Amazon Payments), it uses the entire request URI as the basis for the signature, with encryption based on the unique security credentials for your account.

For outbound requests (from Amazon Payments to your application), Amazon signs the response which you can verify using the VerifySignature API

EDIT:

As @Jonathan Spooner mentioned already and what I use is the function varifySignature() located in

/amazon-fps-2010-08-28-php5-library/src/Amazon/FPS/Samples/Client.php

which can be downloaded here. It also has an example as to how to use it in

/amazon-fps-2010-08-28-php5-library/src/Amazon/FPS/Samples/VerifySignatureSample.php

It makes the whole process much easier. It may be worth a shot...

Stoddard answered 19/1, 2012 at 19:44 Comment(2)
this is what I thought too, but their example in the documentation doesn't have the ? character. I'll try it with the ? character just to make sure.Naturalist
Your signature is still not the same as your request URI though... I notice your pipelineName parameter is missing from your signature URI and your parameters are in a different order to that of the request URI. I would suggest try to make your signature a clone of your request URI - obviously without the signature tacked on the end of your signature URI ;)Stoddard
N
1

Have you tried this

base64_encode(hash_hmac('sha256', $Request, $AmazonSecretKey, true));

Pass a boolean to pass it as a raw output.

Neurotomy answered 19/1, 2012 at 19:47 Comment(2)
trying this now...will report in a second.Naturalist
unfortunately, that didn't help :(Naturalist
T
1

You're most definitely missing the last parameter for hash_hmac which has to be set true to get RFC 2104-compliant HMAC signature:

base64_encode(
    hash_hmac($hash, $data, $key, true)
);

And in the complete example you're missing new lines in $string_to_sign.

Technology answered 20/1, 2012 at 7:4 Comment(1)
another commenter suggested I should not have space characters :) I am kind of lost how it should be. Do you have something similar working for you? How did you code it up?Naturalist

© 2022 - 2024 — McMap. All rights reserved.