Tag Archives: Android

Creating a PayPal / Credit Card Payment within an Android Application

By and

In this tutorial we’re going to learn how to set up the PayPal Android SDK to process a simple payment via either a PayPal payment or a credit card purchase. At the end of this example, you should have a simple button in an application that, when clicked, will forward the user to PayPal to confirm a set payment, then return the user back to the application and log the confirmation of payment.

The complete application code for this example is available in the PayPal Developer Github Repository.

Let’s get started.

The first step is to obtain and add the SDK to your project. We add the reference to our build.gradle dependancies like so:

dependencies {
    compile 'com.paypal.sdk:paypal-android-sdk:2.14.1'
    ...
}

Now we head over to our MainActivity.java file (or wherever you’d like to add the PayPal button integration), and add in a config object for our client ID and the environment (sandbox) that we will be using.

private static PayPalConfiguration config = new PayPalConfiguration()
    .environment(PayPalConfiguration.ENVIRONMENT_SANDBOX)
    .clientId("YOUR CLIENT ID");

Now we’re going to create a button in our onCreate(...) method, which will enable us to process a payment via PayPal once clicked.

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final Button button = (Button) findViewById(R.id.paypal_button);
}

We now need to define the functionality for that button. In your res > layout > main XML file you can add the following definition for the button, which will define the text and onClick handler for the button with the paypal_button ID.

<Button android:id="@+id/paypal_button"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:text="@string/paypal_button"
    android:onClick="beginPayment" />

When clicked, the button will call the beginPayment(...) method. We can then add the text for the button to our strings.xml file, like so:

<string name="paypal_button">Pay with PayPal</string>

With the button in place, we now have to handle the button click in order to begin payment processing. Add in the following beginPayment(...) method below our previous onCreate(...) method.

public void beginPayment(View view){
    Intent serviceConfig = new Intent(this, PayPalService.class);
    serviceConfig.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    startService(serviceConfig);

    PayPalPayment payment = new PayPalPayment(new BigDecimal("5.65"), 
        "USD", "My Awesome Item", PayPalPayment.PAYMENT_INTENT_SALE);

    Intent paymentConfig = new Intent(this, PaymentActivity.class);
    paymentConfig.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    paymentConfig.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);
    startActivityForResult(paymentConfig, 0);
}

What we are doing here is first setting up the service intent (serviceConfig), using the config that we had defined previously for our client ID and the sandbox environment. We then specify the payment object that we want to process. For the sake of this example, we are setting a static price, currency, and description. In your final application, these values should be obtained from what the user is trying to buy in the application. Lastly, we set up the paymentConfig, adding in both the config and payment objects that we had previously defined, and start the activity.

At this point the user will be presented with the PayPal login and payment screens, allowing them to select whether to pay with PayPal or a credit card (via manual entry or card.io if the camera is available). That screen will look something like this:

PayPal payment confirmation screen

Once done, we need to have a handler ready for when PayPal forwards the user back to the application after confirmation of payment or cancellation. Let’s override onActivityResult(...) for that purpose.

@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
    if (resultCode == Activity.RESULT_OK){
        PaymentConfirmation confirm = data.getParcelableExtra(
            PaymentActivity.EXTRA_RESULT_CONFIRMATION);
        if (confirm != null){
            try {
                Log.i("sampleapp", confirm.toJSONObject().toString(4));

                // TODO: send 'confirm' to your server for verification

            } catch (JSONException e) {
                Log.e("sampleapp", "no confirmation data: ", e);
            }
        }
    } else if (resultCode == Activity.RESULT_CANCELED) {
        Log.i("sampleapp", "The user canceled.");
    } else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
        Log.i("sampleapp", "Invalid payment / config set");
    }
}

Within the onActivityResult(...) method, we are checking to see if the resultCode that comes back is RESULT_OK (user confirmed payment), RESULT_CANCELED (user cancelled payment), or RESULT_EXTRAS_INVALID (there was a configuration issue). In the case of a valid confirmation, we get the object that is returned from the payment and, in this sample, log it. What will be returned to us should look something like the following:

{
    "client": {
        "environment": "sandbox",
        "paypal_sdk_version": "2.14.1",
        "platform": "Android",
        "product_name": "PayPal-Android-SDK"
    },
    "response": {
        "create_time": "2016-05-02T15:33:43Z",
        "id": "PAY-0PG63447RB821630KK1TXGTY",
        "intent": "sale",
        "state": "approved"
    },
    "response_type": "payment"
}

If we look under the response object, we can see that we have a state of approved, meaning that the payment was confirmed. At this point, that object should be sent to your server to confirm that a payment actually went through. For more information on those steps, see these docs.

Our last step is to cleanup in our onDestroy(...).

@Override
public void onDestroy(){
    stopService(new Intent(this, PayPalService.class));
    super.onDestroy();
}

That’s all there is to it. In this example we’ve created a simple button to process a payment with either PayPal or a credit card. From this point, there are a few next steps for you to expand upon this sample:

  • Pulling in payment information dynamically based on user product selection in the beginPayment(...) method.
  • Sending the payment confirmation to your server and verifying that the payment actually went through.
  • Handling the error and cancellation user cases within the app.

Key Pinning in Mobile Applications

By and

On Tuesday, October 13, 2015, Hubert Le Van Gong of the PayPal Ecosystem Security team gave a presentation to our developer community on SSL key pinning as it applies to mobile application development. I had a chance to interview him before the presentation to discuss the value and proper methods for incorporating key pinning in Android and IOS app development. Highlights of the interview along with Hubert’s recommended approach for key pinning on each platform are below. For follow up questions please contact Hubert Le Van Gong.

What is key pinning and how does it fit into the overall mobile application development process?

The goal of key pinning is to prevent web browsers or mobile applications from accepting an imposter’s TLS certificate that is used to pose as a legitimate service provider like PayPal. When a client attempts to establish a TLS connection with a server, it has to validate the certificate chain of trust. That chain of trust validation is primordial in PKI (Public Key Infrastructure) and uses cryptography to assess trust in the connection between a client and a server. A certificate chain of trust consists of a certificate issued by a root CA (certificate authority), a sequence of one or more certificates issued by intermediate CAs, and a leaf certificate (the one directly associated to the server). A root CA issues certificates to intermediary CAs and its certificate is the most stable and trusted in the trust chain (browsers and OS come pre-loaded with a long list of root CAs). Intermediate CA certificates exist as a layered defense and are stand-ins for the root certificate. Because an intermediate CA’s certificate is signed by the root cert which is stored offline (or chains back to such intermediate CA certificate), they have the authority to issue leaf certificates. In other words, the trust put in root certificate authorities is propagated down this certificate chain to the leaf certificate which is exposed to TLS clients.

Key pinning is the process of matching value(s) derived from a server’s chain of trust, as seen when the TLS connection is established, with pre-loaded values, derived from the expected chain of trust. If no common values are found, the TLS connection must be immediately terminated. Various approaches existed based on which part of a certificate should be used for generating those hash values, but the Subject Public Key Info, or SPKI is the standard method in the browser world (as per IETF’s RFC 7469, also known as HPKP, published in April this year) and I recommend using the same for applications. By calculating a SHA1 or, preferably, a SHA256 hash of the SPKI and pinning to that value, developers can ensure their apps connect to a server identified by a bona fide certificate and not a fraudulent one. While the fundamentals of key pinning apply to both the web platform realm and the mobile applications world, I’ve focused on the latter in order to provide the most value for the PayPal developer community.

Is this a real threat or an academic theory?

The threat is very real. Key pinning became a popular concept in 2012 after a series of fraudulent certificate-based hacks revealed yet another hole in the PKI infrastructure. The earliest relevant presentation I could find was a 2009 Black Hat presentation titled, New Tricks for Defeating SSL in Practice. Additionally, 2011 was a particularly rough year for CAs. DigiNotar, a Dutch CA suffered a devastating security breach resulting in over 500 fake certificates being issued, including certificates for some major internet domains like Google.com. The certificates were real from the point of view that they seemed to have been legitimately issued and validated properly. However, armed with those fraudulent certificates the attacker could easily perform man-in-the-middle attacks as well as spoof content etc. These are real world examples of large-scale attacks that cost millions to clean up and ultimately have damaged the trust between CAs and their customers. We see key pinning as one of the most promising approaches to address this lack of trust and provide an extra layer of security on top of TLS.

There are several certificates in the trust chain that developers can chose to pin to. Which is the best to pin to?

To clarify, the server is the one in control when it comes to which certificates should be used for pinning. The developers will incorporate whatever values are advertised by the server. Theoretically, it is possible to pin to certificates at all three levels: the end server (AKA leaf) cert, an intermediate CA cert, and the root CA cert. By pinning to two or more of these certificates, you’re ensuring that your site or service doesn’t get “bricked” because the only value you were pinning to has changed. Such change may happen as the result of the lost private key (yes, it can happen) or even a server misconfiguration. In that case, if no other pin is available, the service will be inaccessible to any client during the life of the (bad) pin’s policy. Pinning to a leaf certificate is usually not a good idea because those certificates will change more frequently. Intermediate CA certificates are OK to pin to, but one has to be cautious to avoid cross-signed certificates since they could alter the validation path. Root CA certificate are probably best. Therefore, when pinning to multiple values (e.g. 2), intermediate CA – root CA is a sound approach in my opinion. That said, it is also perfectly OK to only pin to a single certificate as long as that certificate is a root CA. Whatever the number of pin values, a backup pin is an absolute must-have. Note that the existence of a backup pin is a mandate in HPKP (i.e. for the web case) but it is equally important in the mobile app space. In both cases, the key pair corresponding to the backup pin should be kept offline until an issue arises with the primary pin/key.

Are there examples of improper key pinning?

Absolutely. As explained above, pinning to a single leaf (or even intermediate CA) certificate is not recommended. When it comes to what part of a certificate we should pin to, using the whole certificate is problematic because some fields might change. Although pinning solely to the public key of the certificate might seem like a good idea, there are some crypto risks associated to it so, similarly to what is specified in HPKP, applications should pin to the SPKI part of a certificate.

In your presentation, you discuss several methods for key pinning for Android and IOS. Can you give an example of proper pinning for each?

Sure. First, I want to mention a couple best practices to ensure successful pinning. It is important to note that in order to properly pin, applications must include all values in their pinning set. At this time, PayPal uses four values because we’ve recently transitioned from SHA1 root certificates to SHA256 ones and we have the backup values. If we were pinning to two certificates, we would have eight values. Again, the SHA1 or SHA256 sets can be used but SHA256 is recommended since that’s what is used in HPKP and SHA1 is on its way out anyway. Second, try to leverage the includeSubDomain directive as much as possible (as defined in HPKP). Fewer well-executed pins equal less chance of failure. Practice good pin hygiene!

Android Method

The simplest approach is to use a JSEE-based method as shown below. This is the recommended approach for Android. The method’s input arguments are an HTTPS connection and a set of valid pins for the targeted URL.

Android Method for Key Pinning
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private boolean validatePinning(HttpsURLConnection conn, Set<String> validPins) {
    try {
        Certificate[] certs = conn.getServerCertificates();
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        for (Certificate cert : certs) {
            X509Certificate x509Certificate = (X509Certificate) cert;
            byte[] key = x509Certificate.getPublicKey().getEncoded();
            md.update(key, 0, key.length);
            byte[] hashBytes = md.digest();
            StringBuffer hexHash = new StringBuffer();
            for (int i = 0; i < hashBytes.length; i++) {
                int k = 0xFF & hashBytes[i];
                String tmp = (k<16)? "0" : "";
                tmp += Integer.toHexString(0xFF & hashBytes[i]);
                hexHash.append(tmp);
            }
            if (validPins.contains(hexHash.toString())) {
                return true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
    return false;
}

The pins are declared as strings. For instance:

Declaring Key Pins

1
2
3
4
private static final Set<String> PINS = new HashSet<String>(Arrays.asList(
        new String[]{
                "996b510ce2380da9c738...87cb13c9ec409941",
                "ba47e83b1ccf0939bb40d2...edf856ba892c06481a"}));

Leveraging the above method, here is an example showing how this can be put to use. The only relevant portion is highlighted below.

Example Using Key Pinning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
protected String doInBackground(String... urls) {
    try {
        /** Test pinning given the target URL **/
        /** for now use pre-defined endpoint URL instead or urls[0] **/
        Log.i(LOG_TAG, "==> PinningTestTask launched.");
        String dest = defaultEndpoint;
        URL targetURL = new URL(dest);
        HttpsURLConnection targetConnection = (HttpsURLConnection) targetURL.openConnection();
        targetConnection.connect();
        if (validatePinning(targetConnection, PINS)) {
            final String updateText = "Key pinning succeded for: " + dest;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    textView.setText(updateText);
                }
            });
        } else {
            final String updateText = "Key pinning failed for: " + dest;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    textView.setText(updateText);
                }
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
        final String updateText = "Key pinning failed for: " + dest + "\n" + e.toString();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textView.setText(updateText);
            }
        });
    }
    return null;
}

iOS Method

For iOS, I find DataTheorem’s TrustKit very elegant (developed in collaboration with Yahoo!). It is very easy to integrate with an iOS application: there is no need to update all the classes of the application where https connections are established and instead, there’s at most one API call made during the application’s initialization (because they use a code injection approach). Alternatively (and presumably even easier), it is possible to simply include TrustKit in the manifest file of the bundle and, voilà, key pinning is enabled. For these reasons using TrustKit is our internally recommended approach on iOS. Note that it is currently only available in Objective-C but I have no doubt a Swift version should be coming soon (to meet Apple’s strong push for Swift).

There is a configuration file used to define pinned keys and policies. Interesting detail: in addition to the key hash, the key algorithm must be specified because iOS does not provide developers with an API to easily parse X.509 certificates… So TrustKit needs that info to easily reconstruct the SPKI info. Apparently, most other iOS libraries that provide key pinning only allow pinning to the raw key because it’s easier (even though this is not recommended as explained above).

Another interesting aspect of their approach is that they essentially mimic HPKP functionality (URL for reporting errors, no-enforcement flag) in their configuration file, but from a client app standpoint.

The library supports both application and browser-based (think webview) TLS pinning. It is available on iOS and OS X and was open sourced in August during the BlackHat conference. The implementation directly leverages the low-level SecureTransport framework which is a good thing since SecureTransport seems to be a pretty robust SSL implementation.

The example below shows how TrustKit can be leveraged by simply adding some configuration code to the DidLoad( ) method.

iOS Key Pinning with TrustKit

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)viewDidLoad {
    [super viewDidLoad];
    NSDictionary *trustKitConfig;
    trustKitConfig = @{
                       @"api.paypal.com" : @{
                               kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048],
                               kTSKPublicKeyHashes : @[
                                       @"ukfoOxzPCTm...ft+Fa6iSwGSBo=",
                                       @"mWtRDOI4DanHOM+...MYh8sTyexAmUE="
                                       ],
                               kTSKEnforcePinning : @YES
                               }
                       };
    [TrustKit initializeWithConfiguration
}

Note that the values used above are not direct public key hashes but Base64 encoded values of the SHA256 hashes (following what is defined in HPKP). Upon start, the above code will set up TrustKit and any Https session established with one of the configured URLs (e.g. using NSURLSession) will go through pin validation.

Inside the PayPal Mobile SDK 2.0

By

We’re pleased to announce the 2.0 release of the PayPal Mobile SDK. This major version update introduces important new capabilities as well as improvements under the hood. In this post we’ll highlight a few of the major changes, with some narrative about how we got here.

TL;DR? Check out the PayPal Developer Docs for an overview. In-depth docs and SDK downloads can be found in the PayPal iOS SDK on GitHub or PayPal Android SDK on GitHub.

SDK Focus

In writing the first version of the Mobile SDK last year, our team focused on four high-level values:

  1. Fast and delightful user experience making payments
  2. Simple, equally delightful developer experience taking payments
  3. Consistent, bulletproof quality across devices and platforms
  4. Opendirecttechnical communication between developers (you!) and us

To keep the bar high, we limited the first SDK release to only single payments, using PayPal or credit card (with card.io scanning). While the developers looking for a basic drop-in payment library have found the first version helpful, we knew a complete native mobile payments solution needed to offer more. So, without losing focus on simplicity, quality, and community, we’ve written the 2.0 Mobile SDK to enable seamless commerce in modern, sophisticated mobile commerce and marketplace apps.

Future Payments

The marquee feature in 2.0 is Future Payments. With Future Payments, developers can gather payment information from a customer just once, and use it to process all future payments from that customer. If you’ve added PayPal as a payment option in Uber, then you’ve used it. Uber piloted this feature with us to provide their customers with a PayPal payment option that’s fast and simple. With 2.0, we’re opening up Future Payments to all mobile developers.

So how does it work? To identify who should get paid, you give the SDK a public Oauth2 client_id as input. The SDK then authenticates a user and asks for payment authorization; it returns a short-lived OAuth2 authorization code. Your app sends that authorization code to your servers. Your servers use this code to request OAuth2 access and refresh tokens with the future_payments scope. You can use the access token right away to charge the user, and store the refresh token for the future. Any time that you need to make payment API requests for this user in the future, you can exchange that refresh token for an access token, and you’re off to the races — no need to bother the user again.

Phew! It sounds more complicated than it actually is, and the SDK includes step-by-step integration guides:

Auth & Capture

One frequently requested feature is the option to decouple authorization of a payment from capture at a later time. This is a standard capability offered by credit card gateways. It is useful, for example, when shipping physical goods – you can authorize your customer’s payment when the order is placed, then later capture the funds only when the goods actually ship.

The 2.0 SDK uses new, flexible PayPal REST payment APIs – you can create a payment with either a sale or authorization intent. Thanks to the improved APIs, our team was able to add Auth/Capture support with only minor code changes. And, notably, the intent setting works identically for PayPal and credit card payments.

REST and OAuth 2.0

As PayPal continues to optimize mobile-first platform offerings, the PayPal Mobile SDK team works closely with counterparts in the API teams to set the roadmap and nail the integration with the OAuth2 Identity services and REST Payments API.

The 2.0 SDK now uses only the new PayPal APIs. Migrating to these APIs was critical to making the 2.0 SDK a reality. Now that we’re on the new stack, the SDK is well positioned to gain new capabilities in pace with the platform. We look forward to adding further improvements!

Check it Out

Learn more about the 2.0 PayPal Mobile SDKs by checking out the PayPal Developer Docs. When you’re ready to take a look at the APIs, sample code, README, and integration docs, head on over to GitHub:

We’d love to hear your integration experience and feedback.

About the PayPal SDK Team

We’re a distributed team (Portland, Austin, San Jose) that creates great tools for developers and delightful experiences for their users. When not releasing sweet PayPal SDKs, we can be found variously drinking copious amounts of coffee, writing science fiction, biking long distances, snuggling with a Ziggy, or driving down the California coast. Want to get in touch or see what we’ve worked on? Find us on GitHub: DaveBrentTomMattJeffJuwonAviJosh, AbhijeetMikeAvijit, Roman, and Bunty.