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:
- Verify initiatePaymentSession and initiateRefundSession APIs
- Generate checksum by creating hash of payload body of these requests using HMAC algorithm and signed using
Extension API Secret
. - 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.
- Generate checksum by creating hash of payload body of these requests using HMAC algorithm and signed using
- Passing checksum in updatePaymentSession and updateRefundSession API.
- Generate
checksum
by creating a hash of request body using HMAC algorithm and signed usingExtension API Secret
. - Pass the checksum generated in the previous step in the request body when calling updatePaymentSession and updateRefundSession API.
- Fynd Commerce validates API requests using this checksum.
- Generate
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);
- Verify getPaymentStatus and getRefundStatus API
- Generate
checksum
from payment transaction IDgid
parameter received in these API requests using HMAC algorithm and signed usingExtension API Secret
. - 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.
- Generate
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)
- Verify getActivationReadiness API
- Generate
checksum
by encodingExtension API Secret
using base64 encoding. - 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.
- Generate
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.
Follow our Best Practices Guide for additional best practices on developing extensions.