Validating Cordova In App Purchases on iOS and Android Using Node.js

After integrating in app purchases to a cordova app, you need to validate the transactions on the server using the purchase receipt.

It is not critical (but still recommended) to validate non-consumable purchases, that unlock a feature for example, because even if someone fakes such a purchase, it will usually affect only their device.

However, it is important to validate consumable purchases, such as credits or coins, because fake transactions can affect other users, and deflate your application's currency.

After making a purchase using the buy() function, you will get the values that you need to send to your server for validation.

  • on iOS - you only need to use the receipt attribure.
  • on Android - you need to use the receipt attribute, which will be a string containing a json of the purchase information, and the signature attribute.

voltrue2/in-app-purchase is a node.js library that validates purchases with Apple's and Google's APIs.

On both platforms, you can send the receipt for either sandbox or production and the validation will work. However, you need to check which environment the transaction was made on before giving away credits.

iOS Setup

For iOS, the itunes shared secret is only required for subscriptions validation. If you are validating consumable or non-consumable products, you don't need to include it.

The data parameter that you will pass to the validate function, has to be a string of the purchase receipt.

iOS setup example:

var iap = require('in-app-purchase');
var validationType = iap.APPLE;
iap.config({ applePassword: config.itunesSecret });
var data = req.body.receipt;

Android Setup

On Android, the google play public key is required for all validations. You can specify different keys for sandbox and production, or use the production one for both.

The data parameter that you will pass to the validate function, has to be an object containing the receipt (a string with the json of the purchase details as returned from the plugin's buy function) and the signature.

Android setup example:

var iap = require('in-app-purchase');
var validationType = iap.GOOGLE;
iap.config({ googlePublicKeyStrSandBox: config.googleKeySandbox, googlePublicKeyStrLive: config.googleKeyLive });
var data = { receipt: req.body.receipt, signature: req.body.signature };

Validation

After the configuration is set up, the validation is the same for both platforms:

iap.setup((err) => {
  if (err) {
    console.log(err);
  } else {
    iap.validate(iap.APPLE, data, (err, response) => {
      if (err) {
        console.log(err);
      } else {
        if (iap.isValidated(response)) {
          var purcahseDataList = iap.getPurchaseData(response);
        }
      }
    });
  }
});

purchaseDataList will be an array of all the transactions. On iOS, a receipt can contain multiple transactions. On Android, it will always be an array with one item.

Each item in the array will have the following attributes:

  • bundleId (Apple only) - you must compare it to your bundle id to make sure this is a receipt generated by your app.

  • orderId (Android only) - same as bundleId but for Android.

  • productId - you must make sure that this is one of the products you offer, and only give this user credits if the productId is familiar.

  • transactionId

  • purchaseDate

  • quantity

You also must check that the receipt does not already exist in your database. The same receipt can be validated an unlimited number of times and be valid.

Follow me for updates on similar new posts I write or tweet about this post.