Security & Validation

Hook your server code to validate your merchants/users before any financial transaction and secure critical data

You can use the debit-hook feature of the widget to add your own functionality (such as validation or authentication) before any financial transaction (where a wallet has to be debited).

For example,

  • Validate your merchant's wallet to ensure he/she has sufficient funds before any financial transaction
  • Secure critical transaction data on your server to prevent any fraud
  • Store & track the initial state of financial transactions in your server (you get the final success/failure state of the transaction in eko-response callback)

🚧

Please Note:

To avoid any frauds, you should implement merchant authentication (password / OTP / etc) before any transaction where the merchant's wallet has to be debited.

Step 1: Add listener for the 'debit-hook' javascript event

The debit-hook event will be called before any transaction where your merchant's wallet has to be debited (for example, before money-transfer or new-recipient-account-verification).

You can add a listener for the event in Javascript like this:

document.querySelector('#ekowidget').addEventListener('debit-hook', function(e) {
		// Rest of your code to call your server and handle debit-hook...
  	// You get transaction related information in e.detail
});

You get the following information in e.detail:

// e.detail =
{
    "url": "https://staging.eko.in:25004/ekoapi/v1/transactions",
    "http_method": "POST",
    "interaction_type_id": 221,
    "interaction_label": "Send Cash",
    "body": "client_ref_id=1527237883837&amount=1000&channel=2&recipient_id=10009977&customer_id=8888888888",
    "client_ref_id": "1527237883837",
    "data": {
        "amount": "1000",
        "channel": "2",
        "recipient_id": 10009977,
        "customer_id": "8888888888"
    }
}

In e.detail, the most important parameters are:

  • interaction_type_id: it tells which transaction this is. You will do validation and generate request_hash based on this value.
  • client_ref_id: this is the unique reference for each transaction. If you do not receive any response from Eko (say, due to network error), you will use this id to check transaction status. You must save this in your database. Or, you can also generate and return your own unique ID for the transaction entry you make in your database and send it to the widget (check next step) as client_ref_id.
  • data: it contains all transaction parameters, such as the amount.

After firing this event, the widget will wait for your consent before moving forward.

Step 2: Validate the transaction & generate secretKey, secretKeyTimestamp and request_hash

In the debit-hook callback function (as per the previous step), call your server with e.detail and then do the following:

  1. Validate the transaction. For example, check if your merchant has enough wallet balance to debit his account.
  2. Block the transaction amount. Debit your merchant's account with the transaction amount.
  3. If previous steps are successful, generate secretKeyTimestamp and secretKey. Check the Authentication section for details & sample code.
  4. Using the same secretKeyTimestamp (as in the previous step), generate the request_hash.
  5. Return the generated values (secretKey, secretKeyTimestamp & request_hash) to your frontend.

HOW TO GENERATE "request_hash"?

The request_hash is generated in the same way as secret_key.

Check the Authentication section on how to generate the hash. But, along with the secret-key-timestamp, we also attach (concatenate) to it other important parameter values in the same order as mentioned below:

Transactioninteraction_type_idData for generating request_hash
Domestic Money Transfer221secretKeyTimestamp + customer_id + recipient_id + amount
Verify Recipient Bank Account (Domestic Money Transfer)149secretKeyTimestamp
Indo-Nepal Money Transfer279secretKeyTimestamp + customer_id + recipient_id + amount

For example, for Money Transfer (or, Indo-Nepal), if secret-key-timestamp=1234567890, customer_id=9876654321, recipient_is=1234 & amount=10000, then to get request_hash, pass the following string in the function to generate hash: "12345678909876654321123410000".

Now, get Base64 encoded HMAC_SHA256 of "12345678909876654321123410000". Check the Authentication section for the sample code to generate the hash (Same code that is used to generate the secret-key).

❗️

IMPORTANT

The request_hash is only generated for a valid transaction that you want to commit. NEVER generate request_hash for an invalid transaction that you want to cancel!

If you are using .NET, you should not send overly specific time stamps, due to differing interpretations of how extra time precision should be dropped. To avoid overly specific time stamps, manually construct dateTime objects with no more than millisecond precision.

Step 3: Confirm or cancel widget transaction

If Step 2 fails (for example, not enough balance in your merchant's wallet), cancel the widget transaction by using the following Javascript code in your frontend:

document.querySelector('#ekowidget').go(false, {message: "You have insufficient balance"});

If Step 2 is successful and you receive secretKey, secretKeyTimestamp and request_hash from your backend server, use the following Javascript code to confirm the widget to proceed with the transaction:

document.querySelector('#ekowidget').go(true, 
                       {
  												request_hash:"...", 
                        	secretKey:"...", 
  												secretKeyTimestamp:"...",
  												client_ref_id:"..."				// OPTIONAL
						});

NOTE: the client_ref_id parameter is optional. If you want us to use your own unique transaction id as client_ref_id, pass it here.

<html>
<body>

  <!--
		This code will go at the end of the same page where you have inserted the tf-eko-connect-widget from the previous "How to Integrate Widget?" step:

			<tf-eko-connect-widget id="ekowidget" ... ></tf-eko-connect-widget>
	-->

	<script>

		// CAPTURE EKO WIDGET DEBIT-HOOK
		document.querySelector('#ekowidget').addEventListener('debit-hook', function(e) {

			console.log("[ON DEBIT HOOK] Transaction Data = ", e.detail);

			// SEND DATA TO YOUR SERVER TO DO THE FOLLOWING:
				// 1. Get transaction details in "e.details"
				// 2. VALIDATE: check user wallet balance
				// 3. IF TRANSACTION IS VALID, generate request_hash, secretKey & secretKeyTimestamp 
				//    from your server (depending on e.detail.interaction_type_id)

			$.ajax({url: 'https://MYTESTSITE.COM/handleDebitHook',
				type: 'post',
				dataType: 'json',
				contentType: 'application/json',
				timeout:60000,
				data: { detail: JSON.stringify(e.detail) },

				success: function (resp) {
					// Response returned from your server is stored in 'resp'
					// Eg: resp = {
					//		continue: true/false,	// Validation passed?
					//		secretKey: "...",
					//		...
					//	}
					console.log("[DEBIT HOOK] My Server Response = ", resp);

					if (resp.continue === true)
					{
						// IF EVERYTHING IS ALLRIGHT, CONTINUE WIDGET...
						document.querySelector('#ekowidget').go(true, {
							request_hash: resp.request_hash, 
							secretKey: resp.secretKey, 
							secretKeyTimestamp: resp.secretKeyTimestamp, 
							client_ref_id: resp.client_ref_id // OPTIONAL
						});
					}
					else
					{
						// IF VALIDATION FAILS, CANCEL WIDGET...
						document.querySelector('#ekowidget').go(false, {
							message: resp.message || "Validation failed"
						});
					}
				},

				error: function(jqXHR, textStatus, errorThrown) {
					console.error("[DEBIT-HOOK] ERROR: ", textStatus, errorThrown);
				}
			});
      
		});
	</script>

	<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
</body>
</html>
<?php

// [SAMPLE CODE] DEBIT-HOOK BACKEND (/handleDebitHook/index.php)
// Validate User's Wallet and Generate secretKey, secretKeyTimestamp & request_hash

header("Content-Type: application/json; charset=UTF-8");


// Initializing key in some variable. You will receive this key from Eko via email
$key = "...";

// Get transaction details sent by the widget
$trxn_data = json_decode($_POST["detail"], false);


// VALIDATE YOUR USER/MERCHANT'S WALLET BALANCE
$continue = validateUser($trxn_data);	// write your own function code

if ($continue)
{
	// VALIDATION SUCCESSFUL...

	// Encode 'key' using base64
	$encodedKey = base64_encode($key);

	// Get current timestamp in milliseconds since UNIX epoch
  // Check out https://currentmillis.com to understand the timestamp format
	$secret_key_timestamp = round(microtime(true) * 1000);

	$data = "";

	if ($trxn_data->interaction_type_id == 221 || $trxn_data->interaction_type_id == 279)	// Money Transfer or Indo-Nepal
	{
		$data = "" . $secret_key_timestamp . $trxn_data->data->customer_id . $trxn_data->data->recipient_id . $trxn_data->data->amount;
	}
	elseif ($trxn_data->interaction_type_id == 149)	// Recipient Bank Verification
	{
		$data = "" . $secret_key_timestamp;
	}

	// Computes the signature by hashing the salt with the encoded key 
	$signature_secret_key = hash_hmac('SHA256', $secret_key_timestamp, $encodedKey, true);
	$signature_req_hash = hash_hmac('SHA256', $data, $encodedKey, true);

	// Encode it using base64
	$secret_key = base64_encode($signature_secret_key);
	$request_hash = base64_encode($signature_req_hash);

	//echo $secret_key;
	//echo $secret_key_timestamp;
	//echo $request_hash;
	
  // Return all generated values as a JSON resonse
	json_encode(array('continue' => True, 'secretKey' => $secret_key, 'secretKeyTimestamp' => $secret_key_timestamp, 'request_hash' => $request_hash));
}
else
{
	// VALIDATION FAILED...

  // Return transaction-failed respose
	json_encode(array('continue' => False, 'message' => 'Validation failed'));
}

?>