Home > flex, payment gateways, tutorials > Using Amazon Flexible Payment System with Flex

Using Amazon Flexible Payment System with Flex

July 11th, 2009

Amazon FPS is a popular and powerful payment service and in this paper I will discuss how you can integrate Amazon FPS into a RIA while preserving the high level of security required for these type of integrations. Amazon FPS is designed to integrate with standard, request-based web applications. While this request-based paradigm is successfully used by a lot of current web applications, Rich Internet Applications with the Single Page paradigm have proved to be better suited for many e-commerce workflows and use cases.

To better illustrate let’s consider the following scenario:

John visits onDemand.tv, a new on demand video site. He chooses to watch The Matrix. Just when Neo is asked to choose between the red and blue pill, the movie pauses and John is asked for $1, the fee for watching premium content on onDemand.tv. John, being already trapped in the action, decides to pay the amount using Amazon Payments. After the transaction is completed John happily enters The Matrix.

Security Considerations

One reason for the success of e-commerce is that the Internet has proven to be a secure medium for transferring money and making payments. Amazon FPS uses several security elements to make sure that all the payment processed through the service are as secure as possible:

  • Usage of https for communicating with Amazon FPS Web Services ensures that the communication is protected from third party access.
  • A signature mechanism based on Access Keys and Secret Keys ensures that each Seller is uniquely identified.
  • A co-branded page hosted on Amazon servers ensures that the users enter their credentials and pre-approve all the amounts only on the Amazon domain.

Looking at these security elements of Amazon FPS we can make a very important observation regarding protecting the Amazon Secret Key: because Flex is a client technology (and even though the code is compiled into bytecode), hardcoding sensitive information into a Flex App is highly insecure. This means that any signature related computation should NOT be made in Flex and the Amazon Secret Key should NOT under any circumstance be put into a Flex App.

Architectural Approach and UI solutions

Summing this up, our architectural solution has to comply with two concurrent demands:

  • a Flex RIA front-end that is stateful and is built following the Single Page app paradigm
  • the need for security that requires that the Flex App should NOT deal with Amazon Security Key plus the need to go to the Amazon Co-Branded page to authenticate the users

In order to address these we propose the following approach:

  • all payment related processing should be done on the server side so that the Amazon Secret Key will be protected
  • the access to the Co-Branded page should be done in a pop-up page so that the Flex Application will stay in the Single Page Paradigm

Thus the buyer’s experience of Amazon FPS Basic Quick Start using Flex will be like this:

1 John visits onDemand.tv, chooses to watch The Matrix and when Neo has to choose between the Red Pill and the Blue Pill the movie stops and asks for $1. John decides to pay, selects Amazon Payments as the payment method, and clicks Pay Nowclip_image002[1]

Security Note:

Starting from this point it is mandatory that all requests are done through https.

2 After John clicks Pay Now a Pop Up window is opened to the Amazon Co-Branded User Interface (CBUI). This is a standard HTML based Web Application and it’s hosted on the Amazon servers. He signs into his Amazon Payments account using his e-mail ID and password.

clip_image004[1]

3 After he signs in, John views the Payment Method page. This page enables him to select a personal payment instrument, such as his credit card, for the transaction.John selects his Amazon Payments account balance (ABT) as the payment instrument and clicks Continue.

clip_image006[1]

4 After he clicks Continue, John views the Payment Summary page. He reviews the payment details and clicks Confirm.

clip_image008[1]

5 After clicking Confirm, John is redirected to the onDemand.tc company’s web site. The web page he’s redirected to is specified in the returnURL parameter in the co-branded service request. The Return Page contains a “Return to Movie” button.The URL contains additional information including the status of the authorization, and a reference, called the TokenId, to the token stored on Amazon servers. You use that token in Amazon FPS transaction actions (such as Pay) to actually initiate the transfer of money.

Important:

The payment transaction is not initiated by Amazon FPS. The onDemand.tv company must make a Pay web service request with the TokenId that the co-branded service returned earlier.

6 After John clicks “Return to Movie” the Pop Up window closes and the Flex App is notified that the authorization process has ended. Now it can call the Server logic to perform the actual payment and resume the movie so that John will finally enter The Matrix.

Calling the Amazon Co-Branded User Interface

As we said above the Amazon Secret Key needs to stay on the server, so signature processing will be done on the server as well. For these examples we will use PHP as a server language and also the Amazon FPS PHP SDK. Of course you can use any server language, the principles and techniques highlighted here remain the same.

So in order to call the Amazon Co-Branded UI we’ll do the following:

Open a popup window from Flex

//Open the Pop-Up Window first. Using the
//ExternalInterface call we can control the window appereance
ExternalInterface.call('window.open','about:blank','amazonWindow','height=500,width=900,toolbar=no,scrollbars=yes');

Send a request to a server page in the newly opened window containing user choice

var url:URLRequest = new URLRequest("https://miti.pricope.com/testAmazon/startPaymentFlex.php");
url.data = new URLVariables();
var obj:URLVariables = new URLVariables();
url.data.movieId = moviePick.selectedItem.value;
url.data.paymentReason = 'Enter The Matrix';
url.method = "GET";
navigateToURL(url, "amazonWindow");

By using navigateToURL we also assure that if the window.open call doesn’t work (because of a drastic pop-up blocker) we still manage to continue the workflow.

In the server page we generate the Amazon Co-Branded UI Request and redirect the browser to that request (startPaymentFlex.php)

session_start();

function getMovieAmount($movieId) {
//you can replace this function with a more sophisticated one
return 1;
}

$obj = new Amazon_FPS_CBUIUtils(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
$obj->setMandatoryParams("SingleUse", "https://" . $_SERVER['HTTP_HOST'] . "/testAmazon/return.php");
//The refernce ID is unique to your business
//You can replace the standard UID php function with more suitable function
$ref = uniqid("amazon");
$obj->setCallerReference($ref);
$obj->setTransactionAmount(getMovieAmount($_GET['movieId']));
$obj->setPaymentReason($_GET['paymentReason']);
$qs = $obj->getURL() ;
//We use session data to store the state of the application between requests
//The amount will be used later on (in return.php) to invoke the FPS Pay method
//We also hold the status of the transaction. This will be requested
//by the Flex App
$_SESSION['status'] = 'START';
$_SESSION['transaction_amount'] = getMovieAmount($_GET['movieId']);
$_SESSION['movieId'] = $_GET['movieId'];

header("Location:$qs")

Note we also store some data in the session (status, transaction amount and movieId). These variables will be used in the return page to actually invoke the Amazon FPS Pay method.

In a real e-commerce site I strongly suggest that you also log application state in a database. This way you will have access later on to all transaction steps.

Returning from Amazon and making the payment

After the user completes the Amazon Co-Branded page workflow and authorizes the transaction he is redirected to the return page specified in the returnURL parameter in the Co-Branded service request, in our case the return.php page. In this page, after verifying that the returning request is valid I’ve chosen to actually call the Pay method in the Amazon FPS and initiate the money transfer.

For this I used again the Amazon FPS PHP SDK.

function validateQueryString()
{
    echo "validing the query string now\n";
    $querystring = $_SERVER['QUERY_STRING'];
    echo $_GET['signature'];
    $obj = new Amazon_FPS_CBUIUtils(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
    //Original signature received in response from Amazon FPS should be specified.
    $signatureMatched = $obj->validateQueryString($querystring,$_GET['signature']);

    if ($signatureMatched) {
        echo "signature matched \n";
        $request =  new Amazon_FPS_Model_PayRequest();
        //set the proper senderToken here.
        $request->setSenderTokenId($_GET['tokenID']);
        $amount = new Amazon_FPS_Model_Amount();
        $amount->setCurrencyCode("USD");
        //set the transaction amount here;
        $amount->setValue($_SESSION['transaction_amount']);
        $request->setTransactionAmount($amount);
        //set the unique caller reference here.
        $request->setCallerReference($_GET['callerReference']);
        $service = new Amazon_FPS_Client(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
        invokePay($service, $request);
    }
    else
        echo "Signature did not match \n";
}

validateQueryString();

I have used the same invokePay function that can be found in the Amazon FPS PHP SDK, although in the case of a successful transaction I have modified the session variable that stores the status:

function invokePay(Amazon_FPS_Interface $service, $request)
{
     try {
             $response = $service->pay($request);

             echo ("Service Response\n");
             echo ("=======================================================\n");

             echo("        PayResponse\n");
             if ($response->isSetPayResult()) {
                 echo("            PayResult\n");
                 $payResult = $response->getPayResult();
                 if ($payResult->isSetTransactionId())
                 {
                     echo("                TransactionId\n");
                     echo("                    " . $payResult->getTransactionId() . "\n");
                 }
                 if ($payResult->isSetTransactionStatus())
                 {
                     echo("                TransactionStatus\n");
                     echo("                    " . $payResult->getTransactionStatus() . "\n");
                     //CHECK Transaction Status is Success
                     $_SESSION['status'] = 'OK';
                 }
             }
             if ($response->isSetResponseMetadata()) {
                 echo("            ResponseMetadata\n");
                 $responseMetadata = $response->getResponseMetadata();
                 if ($responseMetadata->isSetRequestId())
                 {
                     echo("                RequestId\n");
                     echo("                    " . $responseMetadata->getRequestId() . "\n");
                 }
             }

    } catch (Amazon_FPS_Exception $ex) {
        echo("Caught Exception: " . $ex->getMessage() . "\n");
        echo("Response Status Code: " . $ex->getStatusCode() . "\n");
        echo("Error Code: " . $ex->getErrorCode() . "\n");
        echo("Error Type: " . $ex->getErrorType() . "\n");
        echo("Request ID: " . $ex->getRequestId() . "\n");
        echo("XML: " . $ex->getXML() . "\n");
    }
}

Using ExternalInterface to notify the Flex App

The only thing left now is to notify the Flex application and close the pop-up window.

First we need to prepare the Flex App. We create a payment notification function to be called by the pop-up window. This function is called through ExternalInterace. Because the JavaScript call can be overwritten (using FireBug for instance) the ExternalInterface call is not secure. So we use the call only to notify that the Amazon workflow has ended.

The Status is then retrieved from the server through HTTPS.

private function paymentNotification():void {
	var srv:HTTPService = new HTTPService();
	srv.url = "https://miti.pricope.com/testAmazon/paymentStatus.php";
	srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void {
		Alert.show("Status: " + event.result.status);
	});
	srv.send();
}

In this case paymentStatus.php is a simple php that will only retrieve the status packed in a simple XML format:

session_start();
echo '<status>' . $_SESSION['status'] . '</status>'

This function needs to be explicitly exposed through the ExternalInterface of Flash Player in order to be available to JavaScript calls. This call should be executed when the Flex application finishes initializing. The applicationComplete event is a good candidate for this.

//This will be used by return.php to notify Flex App that the payment has been made
ExternalInterface.addCallback('paymentNotification',paymentNotification);

Back to return.php, the only thing that remains is to close the pop-up window and notify the Flex App.

<script type="text/javascript">
	function gotoflex() {
		window.opener.window.document.getElementById('testAmazon').paymentNotification();
		window.close();
	}
</script>
<form>
<input type="button" value="Close This Window and Return to Flex APP" onclick="gotoflex()"/>
</form>

Installing the sample files

1. Unzip amazonFlexPHP.zip into your Web Root folder (For example: /work/www).

2. Edit amazonFlex/amazon-fps/src/Amazon/FPS/Samples/.config.inc.php and replace

define('AWS_ACCESS_KEY_ID', 'YOUR KEY');
define('AWS_SECRET_ACCESS_KEY', 'YOUR SECREY KEY');

with your own Amazon ACCESS key and SECRET_ACCESS_KEY.

3. In Flash Builder click File->Import … and choose Flash Builder Project.

4. Choose amazonFlex.fxp

5. Fill the the Output Folder Location, Web Root and Root URL with your values. It should look something like this:

image

Categories: flex, payment gateways, tutorials Tags:
  1. April 11th, 2010 at 05:00 | #1

    I keep getting the error “Signature did not match”. (I’ve got a standalone version written in PHP that works fine but your flex/php version fails w/ this error). Also, why do you have “http:” in the flex mxml file but yet you have “https:” in the instructions?

  2. September 5th, 2010 at 17:38 | #2

    Where do I get the SenderTokenId that is required in PaySample.php? The CBUISample file usually contains that but you deleted it for some reason…why?

  3. September 5th, 2010 at 17:41 | #3

    The variables returned in your CBUISample.php file are as follows:

    returnURL,
    pipelineName,
    callerKey,
    version,
    callerReference,
    transactionAmount,
    paymentReason,
    signature

  4. September 5th, 2010 at 18:23 | #4

    did you by chance change the CBUISample.php file?

  5. September 5th, 2010 at 18:44 | #5

    do you recommend that I re-download the files directly from Amazon?

  6. September 5th, 2010 at 20:18 | #6

    the instructions on getting this to work seem incomplete. Do you plan to update this entry anytime soon?

  7. September 5th, 2010 at 21:36 | #7

    I appreciate the tutorial but it’s kind of useless if people can’t use it, right?

Comments are closed.