If you’ve ever had to integrate a payment platform, you know the struggle can sometimes feel real when the company doesn't provide a doc in your preferred language. Recently, I helped ZFB Travel, a travel agency in Kuala Lumpur with Ruby on Rails backend, implement BayarCash, a local Malaysian payment platform. While the documentation provided a PHP example, there was no Ruby version, which left me as a Rails developer scratching head.
Let’s break this down step by step so you can validate a BayarCash checksum in Rails.
The PHP Example
BayarCash’s documentation gives a PHP implementation for generating a checksum. Here’s the snippet they provide:
<?php
$secretKey = 'xxxxx'; // Your API secret key from BayarCash portal
$payloadData = [
"payment_channel" => 1,
"order_number" => "ORD-0060",
"amount" => "60.00",
"payer_name" => "Mohd Ali",
"payer_email" => "mohd.ali@gmail.com"
];
ksort($payloadData); // Sort the payload data by key
$payloadString = implode('|', $payloadData); // Concatenate values with '|'
$checksum = hash_hmac('sha256', $payloadString, $secretKey); // Generate HMAC SHA256 checksum
It’s fairly straightforward: sort the payload, join the values with a pipe (|
), and generate the checksum using HMAC SHA256.
But here’s the problem: if you’re working in Ruby, translating this into Ruby isn’t as intuitive as it seems.
Rails: Validating the Checksum
If you’re part of any local Rails groups, you might’ve seen people struggling with this. Some spend hours debugging this part of the integration. That’s why I’m sharing a clean solution to validate the BayarCash checksum in Ruby on Rails.
Here’s how you can do it:
# Your BayarcashService class
def valid_checksum?(params)
# Extract the received checksum
received_checksum = params['checksum']
# Define the payload data in the exact order specified
payload_data = {
'record_type' => params['record_type'],
'transaction_id' => params['transaction_id'],
'exchange_reference_number' => params['exchange_reference_number'],
'exchange_transaction_id' => params['exchange_transaction_id'],
'order_number' => params['order_number'],
'currency' => params['currency'],
'amount' => params['amount'],
'payer_name' => params['payer_name'],
'payer_email' => params['payer_email'],
'payer_bank_name' => params['payer_bank_name'],
'status' => params['status'],
'status_description' => params['status_description'],
'datetime' => params['datetime']
}
# Sort the payload data by keys (similar to PHP's ksort)
sorted_payload = payload_data.sort.to_h
# Create payload string by joining values with '|'
payload_string = sorted_payload.values.join('|')
# Generate HMAC-SHA256 checksum
generated_checksum = OpenSSL::HMAC.hexdigest(
OpenSSL::Digest.new('sha256'),
SECRET_KEY,
payload_string
)
# Compare checksums (case-insensitive)
ActiveSupport::SecurityUtils.secure_compare(
generated_checksum.downcase,
received_checksum.downcase
)
rescue => e
Rails.logger.error "Checksum validation error: #{e.message}"
false
end
-
Sorting the Payload: Like PHP’s
ksort
, Rails doesn’t have an out-of-the-box method to sort hashes by keys. Usehash.sort.to_h
to get the same effect. -
String Formatting: Join the sorted hash values with a pipe (
|
) to match BayarCash’s requirements. -
Checksum Generation: Use
OpenSSL::HMAC.hexdigest
with the SHA256 algorithm and your secret key to generate the checksum. -
Secure Comparison: Comparing checksums securely ensures there’s no risk of timing attacks. Rails’
ActiveSupport::SecurityUtils.secure_compare
is perfect for this.
Wrapping Up
With this implementation, you’ll be able to validate BayarCash checksums in your Rails app confidently. This approach not only saves you hours of debugging but also makes your integration seamless and secure. Let’s make Rails development smoother, one integration at a time!
Top comments (0)