Passing sensitive data with Secure Requests

Last modified August 21, 2017

Along with basic operations like cart manipulation, coupons or providing "known" customer details Store Builder Library allows you to generate advanced checkout sessions which might contain "authenticated" customer data, custom product pricing or product definitions. This is useful when building customized checkout flows and implies the use of data encryption.

Tip

One example of a way to take advantage of secure requests is to provide customers with a "name your price" or "pay what you want" option on your web pages. Simply design your web site to accept price data from your customers, and use a secure payload to override the products' default prices. Alternatively, this can also be done using the /sessions endpoint of the FastSpring API.

What can be passed as part of secure payload

The payload might contain the following:

  • Customer information / user account ID
  • Custom product pricing and subscription definitions
  • Account management authentication

Passing customer information to be applied to the order in the secure payload

We recommend reading Customer Information, Accounts and single sign-on and Applying Customer Information to the order to familiarize yourself with the concept of Customer Accounts and various options around applying customer information.

This is required when your customer is authenticated with you and your backend is aware of customer details and the details can be passed to the checkout process.

Passing product information in the secure payload

This approach is useful when you want to change a product's price for a specific customer. For example, this might be the case with special pricing or price A/B testing. To do this, you can use  "tags" and "attributes" to pass experiment and variation IDs. Tags provide a way to assign arbitrary key/value pairs to the order and "capture" them later in the order notification.

Both customer and items information can be passed in a single payload.

Passing other order details in the secure payload

In addition to customer and product information, you can also optionally include a coupon, specify the country to be used for the order (which controls the currency for the order) and specify the order language via the secure payload.


Payload example
{
    coupon: <String>,                                       // optional coupon code (not ID) to be applied to the order
    country: <String>,                                      // customer country - pass two-character ISO country code (e.g., "DE" for Germany); controls transaction currency
    language: <String>,                                     // customer language - pass two-character ISO language code (e.g., "DE" for German); controls language used in checkout
}


Authenticating customer to redirect to the Account Management

If your backend is aware of the customer's FastSpring account ID you can generate a pre-authenticated URL and redirect customer to the account management area without the additional validation. 

Encrypt the following JSON on the backend:

{
  "account": "ID obtained from FS",
  "timestamp":  1427419618678  /* epoch time in milliseconds */
}

And call fastspring.builder.authenticate(securedData, secureKey) method passing secure data and secure key as described below. The customer will be redirected to the account management page.

Flow

  1. Generate Private/Public key pair
  2. Build a JSON object (as string) that contains the required data/actions on your backend.
  3. Generate "Secure Key", encrypt JSON object (as string) using the Private key.
  4. Pass resulting strings (encrypted payload and secure key) to your frontend and assign them to Javascript variables.
  5. Make sure you provided "data-access-key" when initializing the Library, otherwise the secure payload won't be sent. 

Creating encrypted payloads

Setting Up Encryption

  1. In the Dashboard, select the Integrations menu and the Store Builder Library tab. 
  2. Copy the Access Key. This is the access key with which you will initialize the API.
  3. Create a Private/Public certificate pair (see instructions below). Under File Upload, click Choose File and browse to and select the file containing your public certificate.
  4. Click SAVE.

Generating "securePayload" and "secureKey"

One-Time Only - Create Private and Public Keys

  • Create a 2048-bit RSA private key. Do not share this key. You will use the private key PEM file privatekey.pem to create your "secureKey".
openssl genrsa -out privatekey.pem 2048
  • Create a 2048-bit RSA public key. Only share this key with FastSpring. FastSpring will use your public key PEM file publiccert.pem to decrypt your payload.
openssl req -new -key privatekey.pem -x509 -days 3650 -out publiccert.pem

Create Your "Secure Key" and "Secure Payload" for each request

When preparing a secure request encrypt your generated payload.

Using Java

  • Create a new random 16-byte aesKey for each payload.
final KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
final SecretKey secretKey = keyGenerator.generateKey() ;
final byte[] aesKey = secretKey.getEncoded() ;
  • Use the random 16-byte aesKey to create the securePayload string from your unencryptedString (typically Base64 string, but could be raw byte[]).
final SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
final Cipher encryptCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
final byte[] cleartext = unencryptedString.getBytes("UTF-8");
final byte[] ciphertext = encryptCipher.doFinal(cleartext);
final String securePayload = Base64.getEncoder().encodeToString(ciphertext);
  • Use your privateKeyPEM string to encrypt your aesKey to create your secureKey string.
final org.bouncycastle.openssl.PEMReader pemReader = new org.bouncycastle.openssl.PEMReader(new StringReader(privateKeyPEM));|
final KeyPair keyPair = (KeyPair) pemReader.readObject() ;
pemReader.close() ;
final PrivateKey privateKey = keyPair.getPrivate() ;
final Cipher clientPrivateCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding") ;
clientPrivateCipher.init(Cipher.ENCRYPT_MODE, privateKey) ;
final byte[] aesKeyEncrypted = clientPrivateCipher.doFinal(aesKey) ;
final String secureKey = Base64.getEncoder().encodeToString(aesKeyEncrypted) ;

FastSpring uses your secureKey string and publiccert.pem to decrypt your securePayload string.

Using PHP

You can also download the working example from here: encryption.php

  • Create a new random 16 byte aesKey for each payload.
$aesKey = openssl_random_pseudo_bytes(16) ; # or urandom() or any other random byte generator
  • Use the random 16 byte aesKey to create the securePayload string from your unencryptedString (typically Base64 string, but could be raw byte[]).
$iv = openssl_random_pseudo_bytes(16) ;
$cipherText = openssl_encrypt($unencryptedString, "AES-128-ECB", $aesKey, OPENSSL_RAW_DATA, $iv) ;
$securePayload = base64_encode($cipherText) ;
  • Use your privatekey.pem file to encrypt your aesKey to create your secureKey string.
$privateKeyFileName = realpath("privatekey.pem") ;
$privateKey = openssl_pkey_get_private("file://$privateKeyFileName") ;
openssl_private_encrypt($aesKey, $aesKeyEncrypted, $privateKey) ;
$secureKey = base64_encode($aesKeyEncrypted) ;

FastSpring uses your secureKey string and publiccert.pem to decrypt your securePayload string.

Passing encrypted payload to the Store Builder Library

Option 1: Build the sessionObject before the API is initialized

This method implies understanding a concept of the Session Object. Refer to Accessing Library from Javascript for more information.

This method works best if a secure payload is available to the page at the moment the page loads. This way you will also apply the data in the first Library call to server.

<script>
var fscSession = {
	'secure': {
		'payload': securedData, // string of encrypted data passed from the server
		'key': secureKey // secure key passed from the server
	}
}
</script>
<!-- placing the session object before the Library is initialized ensures that the data will be sent with the very first request -->
<script
	id="fsc-api"
	src="https://d1f8f9xcsvx3ha.cloudfront.net/sbl/0.7.1/fastspring-builder.min.js" type="text/javascript" 
...

Option 2: Use the fastspring.builder.secure() method after the API is initialized

<script>
	fastspring.builder.secure(securedData, secureKey);
</script>

Testing secure payloads

To simplify the testing process, "Test" storefronts accept unencrypted payloads. Each storefront can be used in both Live and Test modes simultaneously. For example:

To test your payload:

  • Pass JSON as object to your frontend
  • Send JSON object in a secure payload call leaving "key" empty. 

    <script>
    	fastspring.builder.secure(nonEncryptedJSON, '');
    </script>