Skip to main content

Best Practices for Developing Payment Extension

Follow the given best practices for developing Payments extension before starting the development to ensure a smooth, efficient, and maintainable process:

Implement Check Sum Verification

To keep communication between Fynd Commerce and the payment extension secure, Fynd Commerce uses checksum generated using the Extension API Secret to verify communications.

Refer below to know how the payment APIs are verified:

  1. Verify initiatePaymentSession and initiateRefundSession APIs
    1. Generate checksum by creating hash of payload body of these requests using HMAC algorithm and signed using Extension API Secret.
    2. Compare the checksum generated in the previous step with the checksum header received in these API requests. Only if both checksum match, it should proceed with the request.
  2. Passing checksum in updatePaymentSession and updateRefundSession API.
    1. Generate checksum by creating a hash of request body using HMAC algorithm and signed using Extension API Secret.
    2. Pass the checksum generated in the previous step in the request body when calling updatePaymentSession and updateRefundSession API.
    3. Fynd Commerce validates API requests using this checksum.

Example Code for Checksum Generation of Request Payload

const crypto = require("node:crypto");

request_payload = {}
const message = JSON.stringify(request_payload) // body of payload
const secret = "EXTENSION_API_SECRET"
let encodedBytes = Buffer.from(message, 'utf-8');
const hmac = crypto.createHmac('sha256', secret).update(encodedBytes);
const checksum_auth = hmac.digest('hex').toString();
console.log(checksum_auth);
  1. Verify getPaymentStatus and getRefundStatus API
    1. Generate checksum from payment transaction ID gid parameter received in these API requests using HMAC algorithm and signed using Extension API Secret.
    2. Compare the checksum generated in the previous step with the checksum header received in these API requests. Only if both checksum match, it should proceed with the request.

Example Code for Checksum Generation of Transaction ID

const crypto = require("node:crypto");

const message = "gid" // order gid
const secret = "EXTENSION_API_SECRET"
const hmac = crypto.createHmac('sha256', secret).update(message);
const checksum_auth = hmac.digest('hex').toString();
console.log(checksum_auth)
  1. Verify getActivationReadiness API
    1. Generate checksum by encoding Extension API Secret using base64 encoding.
    2. Compare the checksum generated in the previous step with the authorization header received in this API request. Only if both checksum match, it should proceed with the request.

Example Code for Checksum Generation using base64 Encoding of Extension API Secret

const secret = "EXTENSION_API_SECRET";
const basic_auth = "Basic " + btoa(secret);
console.log(basic_auth);

Validate Credentials before Storing to Database

Extension should validate the credentials entered by the seller before saving them into the database. This ensure that the seller provide the correct credentials. If wrong creds are provided, payment will fail for the customer.

Encryption and Decryption

Extension should save the encrypted credentials into the database. This ensure credentials are not leaked. You can do encryption and decryption using the AES-256 algorithm. While storing PG secrets in the extensions database, we recommend to encrypt these secrets and then store it to be secure.

Encryption

This function encrypts the provided code using the AES-256 algorithm in GCM mode, with the provided secretKey and a random initialization vector (enc_iv). It returns the encrypted data, the enc_iv, and an authentication tag to verify the integrity of the encrypted data.

Example

Code snippet needed for all languages : Python , Java , JavaScript , Go
function encrypt(secretKey, msg) {
const key = Buffer.from(decode(secretKey, 'utf-8'), 'hex');
const msgBuffer = Buffer.from(msg, 'utf-8');
const iv = Buffer.from(decode(enc_iv), 'hex');
const cipher = crypto.createCipheriv('AES-256-GCM', key, iv);
const ctBytes = Buffer.concat([cipher.update(pad(msgBuffer, 16)), cipher.final()]);
const ct = encode(ctBytes.toString('hex'));
return {
enc_iv: enc_iv,
gateway_secret: ct,
authTag: cipher.getAuthTag().toString("hex")
};
}

Decryption

The below decrypt function takes the encrypted data, initialization vector, authentication tag, and secret key, and attempts to decrypt it using the AES-256-GCM algorithm. It also verifies the integrity of the decrypted data using the provided authentication tag.

Example

function decrypt(secretKey, data) {
let {enc_iv, gateway_secret, authTag} = data;
const key = Buffer.from(decode(secretKey, 'utf-8'), 'hex');
const iv = Buffer.from(decode(enc_iv), 'hex');
const ct = Buffer.from(decode(gateway_secret), 'hex');

const decipher = crypto.createDecipheriv('AES-256-GCM', key, iv);
decipher.setAuthTag(Buffer.from(authTag, 'hex'))
const decryptedBytes = Buffer.concat([decipher.update(ct), decipher.final()]);
const decDataString = unpad(decryptedBytes.toString('utf-8'));
const decDataObject = JSON.parse(decDataString);
return decDataObject;
}

Audit Trail

You should include an audit trail on the config page to show when the last credentials were changed and who changed them. This is to show the seller that when credentials were created/updated so that he knows if anyone has changed credentials in the past. It can look like this.

info

Follow our Best Practices Guide for additional best practices on developing extensions.


Was this section helpful?