In order to check whether the response received by your client was sent by the Nimbbl server, you need to validate the signature
received as part of the response. To validate this signature, you will also need to generate a signature on your server and then compare the generated signature with the one received from Nimbbl.
- This is a mandatory step to check the veracity of the response received
- It allows you to be protected from tampering frauds
- This should be performed on your server
Attributes for Creating the Signature
The following attributes will be required to generate the signature on your server
Attribute | Description |
---|---|
signature_version | Use the signature_version in the transaction object returned by Nimbbl for the payment in the response |
invoice_id | Use the invoice_id of the order that is generated on your server, returned by Nimbbl in the response |
transaction_id | Use the transaction_id in the transaction object returned by Nimbbl for the payment in the response |
secret_key | The secret_key is generated from the Dashboard. Available on your server |
transaction_amount | Use the transaction_amount in the transaction object returned by Nimbbl in the response. Always use the transaction_amount with 2 decimal places. |
transaction_currency | Use the transaction_currency in the transaction object returned by Nimbbl in the response |
status | Use the status in the transaction object returned by Nimbbl in the response |
transaction_type | Use the transaction_type in the transaction object returned by Nimbbl in the response |
Generating the HMAC Signature
Use the SHA256 algorithm to construct a HMAC hex digest as shown below:
Some JSON libraries convert the whole float numbers to integers (3.0
may be converted to 3
).
Hence, we recommend to always convert the transaction_amount
field into float with 2 decimal places.
However, if the transaction_amount
has more than 2 decimal places, trim the transaction_amount
to 2 decimal places.
For example
- If the
transaction_amount
is 3, use thetransaction_amount
value as 3.00 for signature creation. - If the
transaction_amount
is 3.1, use thetransaction_amount
value as 3.10 for signature creation. - If the
transaction_amount
is 3.12, use thetransaction_amount
value as 3.12 for signature creation. - If the
transaction_amount
is 3.129, use thetransaction_amount
value as 3.12 for signature creation.
- Java
- C#
- PHP
- Python
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
public class HmacUtils {
public static String hmacSha256(String signatureData, String secretKey) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
mac.init(secretKeySpec);
byte[] raw = mac.doFinal(signatureData.getBytes(StandardCharsets.UTF_8));
StringBuilder hexString = new StringBuilder();
for (byte b : raw) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
String signatureVersion = "v3";
String generatedSignature;
String signatureData;
if ("v3".equals(signatureVersion)) {
signatureData = "invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment";
} else if ("v2".equals(signatureVersion)) {
signatureData = "invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR";
} else {
throw new IllegalArgumentException("Invalid signature version");
}
String accessSecret = "<YOUR_ACCESS_SECRET>";
generatedSignature = hmacSha256(signatureData, accessSecret);
String expectedSignature = "d743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259";
if (generatedSignature.equals(expectedSignature)) {
System.out.println("Matched");
}
}
}
using System;
using System.Security.Cryptography;
using System.Text;
class HmacUtils
{
public static string HmacSha256(string signatureData, string secretKey)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey);
byte[] dataBytes = Encoding.UTF8.GetBytes(signatureData);
using (var hmac = new HMACSHA256(keyBytes))
{
byte[] hashBytes = hmac.ComputeHash(dataBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
static void Main()
{
string signatureVersion = "v3";
string generatedSignature;
string signatureData;
if (signatureVersion == "v3")
{
signatureData = "invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment";
}
else if (signatureVersion == "v2")
{
signatureData = "invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR";
}
else
{
throw new ArgumentException("Invalid signature version");
}
string accessSecret = "<YOUR_ACCESS_SECRET>";
generatedSignature = HmacSha256(signatureData, accessSecret);
string expectedSignature = "d743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259";
if (generatedSignature == expectedSignature)
{
Console.WriteLine("Matched");
}
}
}
<?php
function hmac_sha256($signatureData, $secretKey) {
$raw = utf8_encode($signatureData);
$key = utf8_encode($secretKey);
return hash_hmac('sha256', $raw, $key);
}
$signatureVersion = 'v3';
$generatedSignature = '';
$signatureData = '';
if ($signatureVersion === 'v3') {
$signatureData = 'invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment';
} elseif ($signatureVersion === 'v2') {
$signatureData = 'invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR';
}
$accessSecret = '<YOUR_ACCESS_SECRET>';
$generatedSignature = hmac_sha256($signatureData, $accessSecret);
$expectedSignature = 'd743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259';
if ($generatedSignature === $expectedSignature) {
echo "Matched\n";
}
?>
import hmac
import hashlib
def _hmac_sha256(signature_data, secret_key):
raw = signature_data.encode("utf-8")
key = secret_key.encode("utf-8")
return hmac.new(key=key, msg=raw, digestmod=hashlib.sha256).hexdigest()
if signature_version == 'v3':
generated_signature = _hmac_sha256(
"invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR|succeeded|payment",
"<YOUR_ACCESS_SECRET>",
)
elif signature_version == 'v2':
generated_signature = _hmac_sha256(
"invoice_123|order_RoQ7Zl92G2qqB3rg-20210226111026|123.00|INR",
"<YOUR_ACCESS_SECRET>",
)
signature = "d743d28875603deeb206d3d742bec9494c1f61212a84217649f233549a279259"
if generated_signature == signature:
print("Matched")
Comparing the Signatures
The signature you generate on your server should match the signature
returned to you by the Checkout in order to verify that the payment received is from an authentic source.
- V3 Signature
- V2 Signature
If the signature_version
returned in the Webhook/Callback is v3
then verify the signature using the logic mentioned below:
generated_signature = hmac_sha256(invoice_id + "|" + transaction_id + "|" + transaction_amount + "|" + transaction_currency + "|" + status + "|" + transaction_type, <your_secret_key>);
if (generated_signature == signature) {
payment is successful
}
If the signature_version
returned in the Webhook/Callback is v2
then verify the signature using the logic mentioned below:
generated_signature = hmac_sha256(invoice_id + "|" + transaction_id + "|" + transaction_amount + "|" + transaction_currency, <your_secret_key>);
if (generated_signature == signature) {
payment is successful
}
If the signature you generate doesn't match the signature returned to you, please mark the Order as failed on your end. You should also raise a request for an investigation of this order on help@nimbbl.biz