Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Creative tools for business
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / Flex Developer Center /

Integrating PayPal Express Checkout with Flex and Adobe AIR

by Miti Pricope

Miti Pricope
  • http://miti.pricope.com

Modified

22 March 2010

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
Adobe AIR e-commerce Flash Builder Flex

Requirements

Prerequisite knowledge

To follow all the steps in this tutorial you will need general familiarity with Flex and ActionScript 3 as well as PHP. Some knowledge of the PayPal Express Checkout API will also be helpful.

User level

Intermediate

Required products

  • Flash Builder (Download trial)

Sample files

  • PayPalAIRFiles.zip (1695 KB)
  • PayPalFlexFiles.zip (1693 KB)

In this article, I will show you how to integrate PayPal Express Checkout with either a Flex application running in Flash Player or an Adobe AIR application. Express Checkout streamlines the checkout process for PayPal buyers, but there are security implications for using it in stateful applications.

l will review the security and UI considerations, introduce the architectural approach, and then show you how to implement the whole thing. You can also download working samples to see how everything works together.

For server-side scripting, I have used PHP but the techniques outlined here can be extended to any server language.

Starting PayPal Express Checkout from a Flex application running in Flash Player

The primary challenge of integrating payment services into RIAs is that currently payment services such as PayPal are designed to work in the request-response paradigm (the standard paradigm for web-based applications), while RIAs are, of course, stateful.

Consider the following simple RIA payment service scenario.

John visits MitiOnDemand.tv, a new on-demand video site. He decides 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 MitiOnDemant.tv. John, being already caught up in the action, elects to pay the amount using PayPal. After the successful transaction 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. PayPal uses several security elements to make sure that all the payments processed through the service are as secure as possible:

Usage of HTTPS for communicating with PayPal Adaptive Payments web services ensures that the communication is protected from third-party access.

A set of API_USERNAME, API_PASSWORD, and API_SIGNATURE values ensures that the calling party is uniquely identified.

A part of the payment approval process is hosted on the PayPal servers. This is a very important anti-phishing mechanism and ensures that users enter their credentials and approve or pre-approve all the amounts only on the PayPal domain.

When looking at these security elements of the PayPal APIs, one important observation regarding protecting the PayPal API credentials becomes clear: because Flex is a client technology (and even though the code is compiled into bytecode), hardcoding sensitive information into a Flex application is a highly insecure practice. Put simply, any information related to credentials (including the API_USERNAME, API_PASSWORD and API_SIGNATURE values) should NOT be stored in the Flex application.

Architectural approach and UI solutions

Summing this up, the architectural solution has to comply with three concurrent demands:

  • It calls for a Flex RIA front end that is stateful and is built following the single page application paradigm.
  • To be secure, the Flex application must not handle PayPal API credentials.
  • The payment workflow will include a part that is hosted on the PayPal servers and that uses a standard request-response web application.

To meet these requirements, I suggest the following approach:

  • All PayPal API calls will be made from the server side so that API credentials will be protected.
  • Access to the PayPal web application will be from a new pop-up page, enabling the Flex Application to stay in the single page paradigm and preserve its state.
file
Figure 1. The workflow incorporates a RIA front end and PayPal Express Checkout.

The user workflow for the checkout process (see Figure 1) includes the following stages:

  1. The user chooses to checkout using PayPal in the RIA application (see Figure 2).

    Note: To ensure security, all requests must be performed through HTTPS starting from this point in the workflow.

file
Figure 2. The user is presented with the opportunity to pay using PayPal.
  1. The user sees a new window open and logs into PayPal to authenticate his or her identity (see Figure 3).
file
Figure 3. The user logs in to his or her account on the PayPal site.
  1. The user reviews the transaction on PayPal (see Figure 4).
file
Figure 4. On the PayPal site, the user reviews the payment method, address, and contact information.
  1. The user confirms the order and pays from my site (see Figure 5).
file
Figure 5. Back on my site, the user approves the purchase.
  1. The user reviews the order confirmation on my site (see Figure 6).
file
Figure 6. The application reports that the transaction was successful.
  1. The user closes the pop-up and returns to Flex Application (see Figure 7).
file
Figure 7. After clicking Return to Flex, the user is now ready to play the movie.

Calling the PayPal part of the checkout process from Flex

Because the PayPal API credentials need to stay on the server, the PayPal API should be invoked from the server as well. For this tutorial, I use PHP as a server language, and I also use the PayPal Name-Value Pair (NVP) API sample code. Of course, you can use any server language, the principles and techniques highlighted here remain the same.

First, I will open a pop-up window from Flex using the following code:

payPalFlex.mxml

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

In the newly opened window, I send a request to a PHP server page and include the user’s purchase choice:

payPalFlex.mxml

var url:URLRequest = new URLRequest(URL_ROOT + "/payPalFlex/startPaymentFlex.php"); url.data = new URLVariables(); var obj:URLVariables = new URLVariables(); url.data.movieId = '1'; url.data.paymentReason = 'Enter The Matrix'; url.method = "GET"; navigateToURL(url, "payPalWindow");

On the server page, I follow the PayPal NVP samples and generate the URL that will redirect the user to PayPal site.

startPaymentFlex.php

$serverName = $_SERVER ['SERVER_NAME']; $serverPort = $_SERVER ['SERVER_PORT']; $url = dirname ( 'http://' . $serverName . ':' . $serverPort . $_SERVER ['REQUEST_URI'] ); function getMovieAmount($movieId) { //you can replace this function with a more sophisticated one return 1; } $paymentAmount = getMovieAmount($_GET['movieId']); //$_REQUEST ['paymentAmount']; $currencyCodeType = 'USD'; //$_REQUEST ['currencyCodeType']; $paymentType = 'Sale'; //$_REQUEST ['paymentType']; /* The returnURL is the location where buyers return when a payment has been succesfully authorized. The cancelURL is the location buyers are sent to when they hit the cancel button during authorization of payment during the PayPal flow */ $returnURL = urlencode ( $url . '/GetExpressCheckoutDetails.php?currencyCodeType=' . $currencyCodeType . '&paymentType=' . $paymentType . '&paymentAmount=' . $paymentAmount ); $cancelURL = urlencode ( "$url/cancel.php?paymentType=$paymentType" ); /* Construct the parameter string that describes the PayPal payment; the variables were set in the web form, and the resulting string is stored in $nvpstr */ $nvpstr = "&Amt=" . $paymentAmount . "&PAYMENTACTION=" . $paymentType . "&ReturnUrl=" . $returnURL . "&CANCELURL=" . $cancelURL . "&CURRENCYCODE=" . $currencyCodeType; /* Make the call to PayPal to set the Express Checkout token If the API call succeeded, then redirect the buyer to PayPal to begin to authorize payment. If an error occured, show the resulting errors */ $resArray = hash_call ( "SetExpressCheckout", $nvpstr ); $_SESSION ['reshash'] = $resArray; $ack = strtoupper ( $resArray ["ACK"] ); if ($ack == "SUCCESS") { // Redirect to paypal.com here $token = urldecode ( $resArray ["TOKEN"] ); $payPalURL = PAYPAL_URL . $token; header ( "Location: " . $payPalURL ); } else { //Redirecting to APIError.php to display errors. $location = "APIError.php"; header ( "Location: $location" ); }

As you can see in the code above, I store the result of the API call in a session variable to use later.

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

Returning from PayPal and notifying the Flex application

After the user completes the workflow on the PayPal site he needs to complete the payment on my site by confirming the transaction (step 4 of the workflow) and then reviewing the order confirmation (step 5).

Although I could have the user close the pop-up window at this point and continue the workflow in the Flex application, this might not be a good idea because it would add an extra step between payment review on the PayPal site (step 3) and payment approval on my site (step 4).

So I choose to implement the payment approval using standard PHP and HTML and reuse the PHP NVP API samples from PayPal. Specifically, I use the GetExpressCheckoutDetails API (for step 4) and the DoExpressCheckoutPayment API (for step 5). See the sample files for more details on the implementation.

What remains to be done now is to close the pop-up window, return to the Flex application, and verify that the transaction succeeded. To communicate with the Flex application I use the Externalnterface API. However, since ExternalInterface is not a secure communication channel I will use it only to notify the Flex application that the pop-up workflow has ended. The Flex application will then retrieve the status from the server. With this approach, a malicious user will not be able to inject a false status into the Flex application.

First, after I call the DoExpressCheckoutPayment API, I save the results in a session variable:

DoExpressCheckoutPayment.php

$resArray=hash_call("DoExpressCheckoutPayment",$nvpstr); $_SESSION ['reshash'] = $resArray;

In Flex, I have a method that checks the status and determines if the transaction succeeded or failed:

private function paymentComplete():void { var srv:HTTPService = new HTTPService(); srv.url = URL_ROOT + "/payPalFlex/getPaymentStatus.php"; //srv.resultFormat srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void { Alert.show(event.result.status.type); if (event.result.status.type == 'SUCCESS') { currentState = 'Succes'; } else { currentState = 'Fail'; } }); srv.addEventListener(FaultEvent.FAULT,function (event:FaultEvent):void { currentState = 'Fail'; Alert.show(event.message.toString()); }); srv.send(); }

In the code above, getPaymentStatus.php is a simple PHP page that retrieves the status from the DoExpressCheckoutPayment result previously stored in a session variable.

getPaymentStatus.php

<status> <type><?php echo strtoupper ($_SESSION ['reshash'] ["ACK"] ) ?></type> </status>

The paymentComplete method must be explicitly exposed through the ExternalInterface API to make it available to JavaScript calls. This can be done when the Flex application initializes; the applicationComplete event is a good candidate for this.

payPalFlex.mxml

ExternalInterface.addCallback('paymentComplete',paymentComplete);

Finally, the following code closes the pop-up window and notifies the Flex application:

DoExpressCheckoutPayment.php

<script type="text/javascript"> function gotoflex() { window.opener.window.document.getElementById('payPalFlex').paymentComplete(); window.close(); } </script> <a class="home" id="CallsLink" href="javascript:gotoflex()">Return to Flex</a>

Installing the sample files

Follow these steps to install the sample files:

  1. Unzip the PayPalFlexFiles.zip archive and put the files in a temporary location; for example, /tmp.
  2. Copy the payPalFlex folder into your web root folder; for example, /work/www.
  3. Edit payPalFlex/ppNVP/constants.php and find the following lines:
define('API_USERNAME', 'sdk-three_api1.sdk.com'); define('API_PASSWORD', 'QFZCWN5HZM8VBG7Q'); define('API_SIGNATURE', 'A.d9eRKfd1yVkRrtmMfCFLTqa6M9AyodL0SJkhYztxUi8W9pCXF6.4NI');

Replace the values with your own PayPal API_USERNAME, API_PASSWORD and API_SIGNATURE.

  1. In Flash Builder 4 choose File > Import and select Flash Builder Project.
  2. Navigate to the payPalFlex.fxp file and select it
  3. Specify the Output folder location, Web root, and Root URL with values appropriate for your setup. The settings I used are shown in Figure 8; your settings may be different.
file
Figure 8. Specify path variables when importing the project.

Starting PayPal Express Checkout from a Flex application running in Adobe AIR

Note: Because the Flash Player and Adobe AIR implementations described in this article both use Flex, parts of the following discussion repeat concepts introduced earlier.

Although Adobe AIR applications run on the desktop and the local security constraints are different from those in the browser, from a payment gateway point of view things don’t change at all. As with the Flash Player implementation, AIR is a client technology, which makes hardcoding sensitive information into the AIR application a highly insecure practice (even though the code is compiled into bytecode). This means that any credential related information (like API_USERNAME, API_PASSWORD and API_SIGNATURE) should NOT be stored in the AIR application.

Architectural approach and UI solutions

The architectural solution has to comply with virtually the same concurrent demands as the Flex application running in Flash Player:

  • It calls for an AIR front end that is stateful and is built following the single page application paradigm
  • To ensure security, the AIR application should NOT deal with PayPal API credentials.
  • The payment workflow will include a part that is hosted on the PayPal servers and that uses a standard request-response web application.

To meet these requirements, I suggest the following approach:

  • All PayPal API calls will be made from the server side so that API credentials will be protected.
  • Access to the PayPal web application will be from a browser page.

Security Note: Although technically it might be possible to use the HTML container of the AIR runtime, this is an insecure practice because the end user cannot visually verify that he is entering his credentials on the PayPal site. In the browser, the user can check the URL and the security certificate.

In the user workflow for the checkout process, the buyer:

  1. Chooses to checkout using PayPal in the AIR application.

    Note: To ensure security, all requests must be performed through HTTPS starting from this point in the workflow.

  2. Sees a browser window open and logs into PayPal to authenticate his or her identity.
  3. Reviews the transaction on PayPal.
  4. Confirms the order and pays from my site.
  5. Reviews the order confirmation on my site.
  6. Returns to the AIR application.

Calling the PayPal part of the checkout process from AIR

The first step of the PayPal workflow is performed in a browser window. The following code opens a browser window from the AIR application and loads the startPaymentFlex.php page:

payPalAIR.mxml

var url:URLRequest = new URLRequest(URL_ROOT + "/payPalAIR/startPaymentFlex.php"); url.data = new URLVariables(); var obj:URLVariables = new URLVariables(); url.data.movieId = '1'; url.data.paymentReason = 'Enter The Matrix'; url.method = "GET"; navigateToURL(url, "new"); currentState='Wait';

The remaining details for this step are similar to the Flex implementation discussed earlier. See Calling the PayPal part of the checkout process from Flex for more information.

Returning from PayPal and notifying the AIR application

Here again, I follow an approach similar to the one used to return from PayPal to a Flex application. (See Returning from PayPal and notifying the Flex application for more details on steps 4 and 5 of the workflow.)

The key difference lies in how to return to the AIR application (step 6). The ExternalInterface API is not suited for this job but the LocalConnection API can be used to communicate between the browser application and the AIR application. LocalConnection, while more secure than ExternalInterface, can still be exploited using techniques like DNS rewriting. As a result, it is inadvisable to pass sensitive information through it. Furthermore, since the AIR application is independent from the browser, it has a different server session. So a simple notification is not enough; I need to also pass the session id. This is not sensitive information, but it will allow the AIR application to retrieve from the server any sensitive information that the browser application has set.

Take a look at what needs to be done right after the PAY operation is invoked. In the transaction detail page I link to a little Flex application that only communicates with the AIR application. This little application is also used to forward the error and cancel messages. I call it using an anchor fragment.

DoExpressCheckoutPayment.php

<a class="home" id="CallsLink" href="payPalAIRReturn.html#method=doStatus">Return to AIR</a>

This little Flex application contains only code to get the cookie string from the browser (remember I need this to enable the AIR application to connect to the same server session) and send a message through LocalConnection to the AIR application:

payPalAIRReturn.mxml

private var outbound:LocalConnection = new LocalConnection(); protected function application1_applicationCompleteHandler(event:FlexEvent):void { var browserManager:IBrowserManager = BrowserManager.getInstance(); browserManager.init(); var urlObj:Object = URLUtil.stringToObject(browserManager.fragment); if (urlObj.method) { //get the cookie string ExternalInterface.call('eval','window.cookieStr = function () {return document.cookie};') var cookieStr:String = ExternalInterface.call('cookieStr'); outbound.connect("paymentSample"); outbound.send("app#payPalAIR:paymentSample",urlObj.method,cookieStr); outbound.close(); } }

Note that when launching from Flash Builder, the AIR application has no Publisher ID so the connection name is app#payPalAIR:paymentSample. After packaging and installation, the AIR application will get a Publisher ID and the connection name becomes something like this:

app#payPalAIR.F0B3F68E1857B8A07069FED1D0638CAF200F76EB.1:paymentSample

You can determine the publisher ID of an installed AIR application by looking at the META-INF/AIR/publisherid file within the application install directory.

Back in the AIR application I expose the functions through the LocalConnection API:

payPalAIR.mxml

private function initApp():void { //only allow connections from localhost //you need to replace "localhost" with the final domain //where your application will be hosted inbound.allowDomain("localhost"); inbound.client = new Object(); //this is the function that will be called by the Browser App inbound.client.doStatus = doStatus; inbound.client.doError = doError; inbound.client.doCancel = doCancel; //inbound.client. inbound.connect("paymentSample"); }

The methods doStatus(), doError(), and doCancel()receive the cookie string as a parameter. In doStatus() I check the transaction status on the server:

payPalAIR.mxml

private function doStatus(cookieStr:String):void { var srv:HTTPService = new HTTPService(); srv.headers.Cookie = cookieStr; srv.url = URL_ROOT + "/payPalAIR/getPaymentStatus.php"; srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void { Alert.show(event.result.status.type); nativeApplication.activate(); if (event.result.status.type == 'SUCCESS') { currentState = 'Succes'; } else { currentState = 'Fail'; } }); srv.addEventListener(FaultEvent.FAULT,function (event:FaultEvent):void { nativeApplication.activate(); currentState = 'Fail'; Alert.show(event.message.toString()); }) srv.send(); }

In the code above getPaymentStatus.php is just a simple page that gets the status from the session and serializes it in a simple XML format:

getPaymentStatus.php

<?php session_start(); ?> <status> <type><?php echo strtoupper ($_SESSION ['reshash'] ["ACK"] )?></type> </status>

Installing the sample files

Follow these steps to install the sample files.

  1. In Flash Builder 4 choose File > Import and select Flash Builder Project
  2. Navigate to payPalAIR.fxp and select it.
  3. Unzip payPalAIR.zip into your web root folder; for example, /work/www.
  4. Edit payPalAIR/ppNVP/constants.php and find the following lines:
define('API_USERNAME', 'sdk-three_api1.sdk.com'); define('API_PASSWORD', 'QFZCWN5HZM8VBG7Q'); define('API_SIGNATURE', 'A.d9eRKfd1yVkRrtmMfCFLTqa6M9AyodL0SJkhYztxUi8W9pCXF6.4NI');

Replace the defined values with your own PayPal API_USERNAME, API_PASSWORD, and API_SIGNATURE.

  1. In Flash Builder 4, choose File > Import and select Flash Builder Project.
  2. Navigate to payPalAIRReturn.fxp and select it.

Specify the Output folder location (where you have copied the payPalAIR folder in your web root), Web root, and Root URL with values appropriate for your setup. The settings I used are shown in Figure 9; your settings may be different.

file
Figure 9. Specify the correct path variables for your system when importing the project.

Where to go from here

In this article I have demonstrated how to securely implement a payment workflow using PayPal Express Checkout and Flex, running both in Flash Player and in Adobe AIR.

The following resources provide more details on the technologies used in this article:

PayPal Technical Documentation

Documentation on the ExternalInterface class

Documentation on the LocalConnection class

Attributions

This article was developed and authored with feedback and input from PayPal.

Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License

More Like This

  • Creating a rich buying experience with a data-driven RIA
  • Creating desktop applications for the cloud with Adobe Flex, AIR, and Amazon S3
  • Integrating Amazon Flexible Payment Service with Flex and Adobe AIR

Tutorials & Samples

Tutorials

  • Flex mobile performance checklist
  • Flex and Maven with Flexmojos – Part 3: Journeyman
  • Migrating Flex 3 applications to Flex 4.5 – Part 4

Samples

  • Twitter Trends
  • Flex 4.5 reference applications
  • Mobile Trader Flex app on Android Market

Flex User Forum

More
07/25/2011 Flash Player Debug Issues - Safari 5.1 & Chrome 13
04/22/2012 Loader png - wrong color values in BitmapData
04/22/2012 HTTPService and crossdomain.xml doesn't work as expected
04/23/2012 Memory related crashes in Flex application

Flex Cookbook

More
04/06/2012 How to detect screen resize with a SkinnableComponent
02/29/2012 Embed Stage3D content inside Flex application components
02/15/2012 Custom WorkFlow Component
02/09/2012 Using Camera with a MediaContainer instead of VideoDisplay

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement