The process of signing a request is quite simple. It involves sending an HTTP header with a value that is calculated at the time of making the call. Signing API calls allows Khipu to verify that the call indeed comes from a server of the merchant. For this, the "secret" value of the collection account is used. Remember that this value should not be shared with anyone.
To sign an API call, we must send the following HTTP header:
Authorization: receiverId:hash
The value of Authorization
is formed by two values:
- receiverId: It's your merchant identifier. It's part of the credentials.
- hash: It's a value calculated using the "secret", the request type (POST, GET, etc.), the URL of the request, and the values you send to the server.
When a request is sent to the API, Khipu uses the merchant's "secret" to calculate the value of "hash". If the calculated value matches the value sent in the header, the request is accepted.
It is important to note that even if the request is accepted, it may not necessarily work, as the values sent could have issues, such as a negative amount.
The process of generating HASH involves several simple steps. Basically, you must construct a string using the type of request (POST, GET, etc.), the URL of the request, the parameters that will be sent, and their values.
The following is a reference code on how to construct the signature for a "POST" call to the URL "https://khipu.com/api/2.0/payments", using 3 parameters to create a payment.
$receiver_id = your_receiver_id;
$secret = 'secret-key';
$method = 'POST';
$url = 'https://khipu.com/api/2.0/payments';
$params = array('subject' => 'Sample payment'
, 'amount' => '1000'
, 'currency' => 'CLP'
);
$keys = array_keys($params);
sort($keys);
$toSign = "$method&" . rawurlencode($url);
foreach ($keys as $key) {
$toSign .= "&" . rawurlencode($key) . "=" . rawurlencode($params[$key]);
}
$hash = hash_hmac('sha256', $toSign , $secret);
$value = "$receiver_id:$hash";
print "$value";
Integer receiverId = yourReceiverId;
String secret = "secret-key";
String method = "POST";
String url = "https://khipu.com/api/2.0/payments";
String toSign = method.toUpperCase() + "&" + percentEncode(url);
HashMap<String, String> map = new HashMap<String, String>();
map.put("subject", "Sample payment");
map.put("amount", "1000");
map.put("currency", "CLP");
List<String> keys = new LinkedList<String>(map.keySet());
Collections.sort(keys);
for (String key : keys) {
toSign += "&" + percentEncode(key) + "=" + percentEncode(map.get(key));
}
String sign = hmacSHA256(secret, toSign);
String value = receiverId + ":" + sign;
System.out.println(value);
First, we must have all the variables involved: receiverId
, secret
, method
, url
, and params
(the parameters we will send to the server).
Let's go through the steps one by one:
- We need to create a string
toSign
that contains the method (POST). - We add URL to the string separated by
&
. URL must be encoded using percent encoding. In PHP, therawurlencode
function is the equivalent. - We get a list of all parameter names sorted lexicographically.
- We iterate through the list of names, and for each one, we add
&
, the name,=
, and the value. It is very important to note that both the name and the value must be encoded using percent encoding. - Using the obtained string and our secret, we apply the HMAC-SHA256 function. The result obtained is the variable hash. In PHP, the
hash_hmac
function is used. - Now we create the value of the header by concatenating the
receiverId
, a:
, and the hash value.
The last value we obtain is the one we should send in the Authorization header of the HTTP call.
In PHP, calculating HMAC is simple as the native function "hash_hmac" is used. In Java, we need to create our own function to generate the hash. The following is an example implementation:
public static String hmacSHA256(String secret, String data) {
try {
if (secret == null || data == null) {
return "";
}
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKeySpec);
byte[] digest = mac.doFinal(data.getBytes("UTF-8"));
return byteArrayToString(digest);
} catch (InvalidKeyException ignored) {
throw new RuntimeException("Invalid key exception while converting to HMac SHA256");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException exception) {
e.printStackTrace();
}
return null;
}
private static String byteArrayToString(byte[] data) {
BigInteger bigInteger = new BigInteger(1, data);
String hash = bigInteger.toString(16);
while (hash.length() < 64) {
hash = "0" + hash;
}
return hash;
}
PHP provides a native function for percent encoding called rawurlencode
. The following is a reference implementation for Java:
public static String percentEncode(String string) {
if (string == null) {
return "";
}
try {
return URLEncoder.encode(string, "UTF-8")
.replace("+", "%20")
.replace("*", "%2A")
.replace("%7E", "~");
} catch (UnsupportedEncodingException exception) {
throw new RuntimeException(exception.getMessage(), exception);
}
}