How to validate google payment token in nodejs

Viewed 560

I'm trying to validate on backend the payment token that I got from the mobile app which is using google-payments.

The token looks like this:

"{\"signature\":\"MEUCIFGFWxmw/6WRXAqEoZAT7TspkckP/Rd5DtfVfa7NHqJ9AiEA1cK5O/hUENf+npc3lKyI1DsKYMA5gNP77Gmhkie/Q00\\u003d\",\"intermediateSigningKey\":{\"signedKey\":\"{\\\"keyValue\\\":\\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwKVBSYqrKGeBTdL4eXerp+qfUAA3Ie5CINH2aK34iYNpmxn+xDIuD67vthpIRjiKtyGtJvqLHs6MPp3kkru8vg\\\\u003d\\\\u003d\\\",\\\"keyExpiration\\\":\\\"1598399127387\\\"}\",\"signatures\":[\"MEUCIQC0n7zyHhvD8sUJhRa+HOeV6hRl1XscT7wt1G685PxyTAIgTVeq4rR1MFseYZcYJ4nKeNz4BGC9m+ax8i434rCoV6w\\u003d\"]},\"protocolVersion\":\"ECv2\",\"signedMessage\":\"{\\\"encryptedMessage\\\":\\\"nxO5fQEB5MXV+9qBXoCpIlxW+F/e5plpQU2nYM5jIBQipzF9gNU9QOv6NKafJv73FQQsCeKADziRaoJagoRST8NApmnl2wlJAyzWLfJKXWKdVLLwnHdccV0qD2sQypn+mZBu7QyQUK52HEgXPV22ms8/4rLr868gIaA9Lmh5sgal4C78P7qzImRJImK5aGVZlzCwopUfqOVipGqJ2ffTXeKsS44OhF2hgYVpfFSbNIrPJR1J82oPl7sNAYKPIQ3CKySE7Y81VINnIVlq5i8/c7DdxK9zkc1Q0j38tLAnP9rvd0fvuvxEFHjHlJoc3eCZbwLUmPb+PyOoLHVbSJDKAg7f8W8jKLalhMziO5zVPmh3rCjMef7mNHuL4qrSPNSZrQPWWkOZ9T/KC8MCXozzP6YxyIWcmrh0AQzVBTQnMUI/AdWK5xkEJDuSC4sS8DU0VyxDJ0SlQcAr7olDQc5CEdOO57erAYVJcaczgvLhzo4Sz1aoIec3lyQculLNr76qRwdQrXcucKloqLU/anatNVn6ZODJqmo\\\\u003d\\\",\\\"ephemeralPublicKey\\\":\\\"BIi24MIm0uqQ3JoaHQ9mY0tk7z+VV2Uue9zCmxrH+gj/DUwvTRFn0D9g860j7JzsdSTPXKr23CFsKRKvOAypNoU\\\\u003d\\\",\\\"tag\\\":\\\"h41QJdk8uByJnwtKPgZiFQzT4evU4pPDUtpi96tMthk\\\\u003d\\\"}\"}"

There are quite extensive docs about the procedure I should implement on backend to validate that the payload is valid and to decode encryptedMessage which allegedly contains details of the purchase.

These can be found here: https://developers.google.com/pay/api/android/guides/resources/payment-data-cryptography#using-tink

To my surprise, Google Pay only provides code example of how to accomplish this in Java (using tink libray). I would really like to not have to add Java service to a system, which otherwise doesn't have it in the stack.

Ideally I would like to validate and decode using nodejs. But I can also settle for Python if need be. Surprisingly I cannot google out a solution to this one and I already spent hours trying to figure implement this using crypto module.

Does anyone know of a library that can be used or maybe can share code examples?

1 Answers

You can not validate the payload data, but using nodejs you could validate the payload structure using joi.

// https://npmjs.com/package/joi
const joi = require('joi');

const payload = '{"signature":"MEUCIFGFWxmw/6WRXAqEoZAT7TspkckP/Rd5DtfVfa7NHqJ9AiEA1cK5O/hUENf+npc3lKyI1DsKYMA5gNP77Gmhkie/Q00\\u003d","intermediateSigningKey":{"signedKey":"{\\"keyValue\\":\\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwKVBSYqrKGeBTdL4eXerp+qfUAA3Ie5CINH2aK34iYNpmxn+xDIuD67vthpIRjiKtyGtJvqLHs6MPp3kkru8vg\\\\u003d\\\\u003d\\",\\"keyExpiration\\":\\"1598399127387\\"}","signatures":["MEUCIQC0n7zyHhvD8sUJhRa+HOeV6hRl1XscT7wt1G685PxyTAIgTVeq4rR1MFseYZcYJ4nKeNz4BGC9m+ax8i434rCoV6w\\u003d"]},"protocolVersion":"ECv2","signedMessage":"{\\"encryptedMessage\\":\\"nxO5fQEB5MXV+9qBXoCpIlxW+F/e5plpQU2nYM5jIBQipzF9gNU9QOv6NKafJv73FQQsCeKADziRaoJagoRST8NApmnl2wlJAyzWLfJKXWKdVLLwnHdccV0qD2sQypn+mZBu7QyQUK52HEgXPV22ms8/4rLr868gIaA9Lmh5sgal4C78P7qzImRJImK5aGVZlzCwopUfqOVipGqJ2ffTXeKsS44OhF2hgYVpfFSbNIrPJR1J82oPl7sNAYKPIQ3CKySE7Y81VINnIVlq5i8/c7DdxK9zkc1Q0j38tLAnP9rvd0fvuvxEFHjHlJoc3eCZbwLUmPb+PyOoLHVbSJDKAg7f8W8jKLalhMziO5zVPmh3rCjMef7mNHuL4qrSPNSZrQPWWkOZ9T/KC8MCXozzP6YxyIWcmrh0AQzVBTQnMUI/AdWK5xkEJDuSC4sS8DU0VyxDJ0SlQcAr7olDQc5CEdOO57erAYVJcaczgvLhzo4Sz1aoIec3lyQculLNr76qRwdQrXcucKloqLU/anatNVn6ZODJqmo\\\\u003d\\",\\"ephemeralPublicKey\\":\\"BIi24MIm0uqQ3JoaHQ9mY0tk7z+VV2Uue9zCmxrH+gj/DUwvTRFn0D9g860j7JzsdSTPXKr23CFsKRKvOAypNoU\\\\u003d\\",\\"tag\\":\\"h41QJdk8uByJnwtKPgZiFQzT4evU4pPDUtpi96tMthk\\\\u003d\\"}"}';

const parsedPayload = JSON.parse(payload);
const payloadSchema = joi.object(
  {
    signature: joi.number().string().required("'signature' is missing from the payload"),
    intermediateSigningKey: joi.object().required("'intermediateSigningKey' is a required param and it must be an object."),
    protocolVersion: joi.string().trim().required("'protocolVersion' is a required param."),
    signedMessage: joi.string().trim().required("'signedMessage' is a required param."),
  },
);

const payloadValidationResult = payloadSchema.validate(paymentData);

if (payloadValidationResult.error) {
  console.log(payloadValidationResult.error.details[0]);
}
Related