Signature validation

The webhook notification sent carry the x-squad-encrypted-body in the header. The hash value (x-squad-encrypted-body) is an HMAC SHA512 signature of the event payload signed using your secret key.

Sample Function (C#)

using System;
using System.Text;
using System.Security.Cryptography;
using Newtonsoft.Json;
					
public class Program
{
	public static void Main()
	{
				var chargeResponse = new VirtualAccount_VM()
				{
					  transaction_reference = "REFE52ARZHTS/1668421222619_1",
					  virtual_account_number = "2129125316",
					  principal_amount = "222.00",
					  settled_amount = "221.78",
					  fee_charged = "0.22",
					  transaction_date = "2022-11-14T10:20:22.619Z",
					  customer_identifier = "SBN1EBZEQ8",
					  transaction_indicator = "C",
					  remarks =  "Transfer FROM sandbox sandbox | [SBN1EBZEQ8] TO sandbox sandbox",
					  currency = "NGN",
					  channel =  "virtual-account",
					  meta =  new MetaBody_VM()
					  {
						freeze_transaction_ref =  null,
						reason_for_frozen_transaction =  null
					  },
					  encrypted_body = "ViASuHLhO+SP3KtmcdAOis+3Obg54d5SgCFPFMcguYfkkYs/i44jeT5Dbx52TcOvHRp9HlnCoFwbATkEihzv2C8UyPoC38sRb90S5Z9Fq7vRwjDQz/hYi/nKbWA0btPr3A+UXhX1Nu5ek+TL0ENUC8W1ZX/FrowX3HQaYiwe3tU/Kfr2XvAGwT7IAx5CQBhpzL34faHP4jbwSVmSgVYmW5rd2ClWQ7WWJjDMakrqYJva8qd0vhkqSpyz2KywOV9t9zSHRx3VpbvlDsBdkNGr+4Axh/7Gspu3xo9mMOIdv73OzjN4VA/qQP+fQMCjU1pbS8oh81HjwkHjzC5SBhzR8IU8bsmvFUyzJMfDoJuUB+fs09SLW7pdfODwK5vB8LtdKPnAuTPlv5dHVAPeMG/ubtl/HOqCZs4axjuO557srw0GpKk86bwaVKt4IQ17nY/QCJFC273HWU1CawP7d3nQasRZf/TU7ra+fOjQBHQ7Gtz2Pnfp3gLljBKenMT4Cabks1X2/6ZQpd/yGFkloYdS7ZW3kEvrorjcyma4WNDmJfhcdR9XGsom6Y/M/n/gMMa0z2KPbHDRoEBeRYbQHcnu5LnGWzBA4Y4RMSTDesD876PDB1bOnMzNPrWYam6ZVRHz"
				};
				
				String SerializedPayload = JsonConvert.SerializeObject(chargeResponse);
				Console.WriteLine(SerializedPayload);
                string result = "";
                var secretKeyBytes = Encoding.UTF8.GetBytes("sandbox_sk_9ac9418e847972dd45f5fe845b5716ef305589808eda");
                var inputBytes = Encoding.UTF8.GetBytes(SerializedPayload);
                var hmac = new HMACSHA512(secretKeyBytes);
                byte[] hashValue = hmac.ComputeHash(inputBytes);
                result = BitConverter.ToString(hashValue).Replace("-", string.Empty);
				Console.WriteLine(result);
		
				Console.WriteLine(result.ToLower() == "18b9eb6ca68f92ca9f058da7bce6545efb12660cf75f960e552cf6098bb5ee8e71f20331dcfe0dfaea07439cc6629f901850291a39f374a1bd076c4eff1026c8");
	}
}
public class VirtualAccount_VM
{
  public string transaction_reference { get; set; }
  public string virtual_account_number { get; set; }
  public string principal_amount { get; set; }
  public string settled_amount { get; set; }
  public string fee_charged { get; set; }
  public string transaction_date { get; set; }
  public string customer_identifier { get; set; }
  public string transaction_indicator { get; set; }
  public string remarks { get; set; }
  public string currency { get; set; }
  public string channel { get; set; }
  public MetaBody_VM meta { get; set; }
  public string encrypted_body { get; set; }
}
public class MetaBody_VM
    {
        public string freeze_transaction_ref { get; set; }
        public string reason_for_frozen_transaction { get; set; }
    }

Sample Function (node)

const crypto = require('crypto');
const secret = "Your Squad Secret Key";
// Using Express
app.post("/MY-WEBHOOK-URL", function(req, res) {
    //validate event
    const hash = crypto.createHmac('sha512', secret).update(JSON.stringify(body)).digest('hex').toUpperCase();
    if (hash == req.headers['x-squad-encrypted-body']) {
     // you can trust the event came from squad and so you can give value to customer
     } else {
      // this request didn't come from Squad, ignore it
     }
    res.send(200);
});

Sample Function (PHP)

<?php

if ((strtoupper($_SERVER['REQUEST_METHOD']) != 'POST' ) || !array_key_exists('x-squad-encrypted-body', $_SERVER) ) 
    exit();
// Retrieve the request's body
$input = @file_get_contents("php://input");
define('SQUAD_SECRET_KEY','YOUR_SECRET_KEY'); //ENTER YOUR SECRET KEY HERE
// validate event do all at once to avoid timing attack
if($_SERVER['x-squad-encrypted-body'] !== strtoupper(hash_hmac('sha512', $input, SQUAD_SECRET_KEY)))
// The Webhook request is not from SQUAD 
    exit();
http_response_code(200);
// The Webhook request is from SQUAD
$body = json_decode($input);
exit();
?>

Sample Function (JAVA)

package hmacexample;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.json.JSONException;
import org.json.JSONObject;
public class HMacExample {
  public static void main(String[] args) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, JSONException {
    //This verifies that the request is from Squad
      
    String key = "YOUR_SECRET_KEY"; //replace with your squad secret_key
    
    String body = "BODY_OF_THE_WEBHOOK_PAYLOAD"; //Replace with body of the webhook payload
   
    String result = "";
    String HMAC_SHA512 = "HmacSHA512";
    String x-squad-encrypted-body = ""; //put in the request's header value for x-squad-encrypted-body
    
    byte [] byteKey = key.getBytes("UTF-8");
    SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA512);
    Mac sha512_HMAC = Mac.getInstance(HMAC_SHA512);      
    sha512_HMAC.init(keySpec);
    byte [] mac_data = sha512_HMAC.
    doFinal(body.toString().getBytes("UTF-8"));
    result = String.format("%040x", new BigInteger(1, mac_data));
    while (result.length() < 128)  result = "0"+ result;
    if(result.toUpperCase().equals(x-squad-encrypted-body)) {
      // you can trust that this is from squad
    }else{
      // this isn't from Squad, ignore it
    }  
  }
}

Last updated