Securing the flow of data between two endpoints is crucial to prevent unauthorized access, data breaches, and malicious attacks. It ensures data integrity, confidentiality, and authenticity, thus protecting sensitive information from being intercepted or tampered with. Secure communication prevents impersonation and ensures that both parties in the transaction are verified and trusted, thus maintaining the overall security and reliability of the system.
In Veriff’s context, it is important to secure the data flow between the API endpoints and webhook listeners. Veriff uses the X-HMAC-SIGNATURES and allowed IP lists and ranges for that purpose.
X-HMAC-SIGNATURES are a security measure, which Veriff generates for the API requests and webhook listeners, to make sure that the exchanged data has not been tampered with.
When generating a signature, make sure that you sign correct data with you shared secret key. Different API endpoints require you sign different things.
As a rule of thumb:
POST / PATCH endpoints require you sign the request body
GET / DELETE endpoints require you sign the session ID
Check the specific API endpoint's documentation for detailed info.
Prerequisites
If you want to generate the X-HMAC-SIGNATURE for an actual API request, have the following info at hand and use these in your preferred signature generation tool:
API key - use it as
X-AUTH-CLIENT header
shared secret key - use it to sign the payload
content-type header - in Veriff’s API requests case always
application/json
API request’s payload - defined in each endpoint’s headers explanation
→ Use the mock data provided below to test signature generation or validation in your local machine
Generate a X-HMAC-SIGNATURE
There are several ways to do that:
For ease of use, go for a dedicated HMAC signature generator which supports the generation of HMAC-SHA256 signatures, like OpenSLL, OAuth.io or Postman
If you want control and flexibility, you can create a script (see some mock scripts here) or use a command-line tool (a mock openssl script)
If you are familiar with a programming language, you can use built-in cryptographic libraries (see a mock Python example here)
If you need the signature quickly and security is not a priority, you can use an online tool (see an example below)
Do not use sensitive data or expose personally identifiable information (PII) even when testing.
Scripts
Click on the box to expand/collapse
JavaScript example
Here is an example in JavaScript of how you can generate an HMAC-SHA256 hash and the corresponding X-HMAC-SIGNATURE using the built-in crypto module.
const crypto = require("crypto");
const sharedSecretKey = "abcdef12-abcd-abcd-abcd-abcdef012345";
const payload = "{\"verification\":{\"callback\":\"https://veriff.com\",\"person\":{\"firstName\":\"John\",\"lastName\":\"Smith\"},\"document\":{\"type\":\"PASSPORT\",\"country\":\"EE\"},\"vendorData\":\"unique id of the end-user\",\"timestamp\":\"2016-05-19T08:30:25.597Z\"}}";
const hash = crypto
.createHmac("sha256", sharedSecretKey)
.update(payload)
.digest("hex");
const xHmacSignature = hash;
console.log(xHmacSignature);
First, set the shared secret key. Note that the shared secret key is hardcoded to the script, so you should take extra care to keep it secret
Next, prepare the payload data and generate the HMAC-SHA256 hash:
Use the
crypto.createHmac()
method, which takes the algorithm name ("sha256") and the shared secret key as arguments, and returns an HMAC objectCall the
update()
method of the HMAC object with the payload data to update the HMAC with the payload dataThen, call the
digest()
method with the argument "hex" to obtain the hash value in hexadecimal format
Store the X-HMAC-SIGNATURE and output it:
Store the hash value directly in the
xHmacSignature
variableFinally, log the
xHmacSignature
to the console
C# example
This is an example of a script that generates an X-HMAC-SIGNATURE using only the built-in System.Text.Encoding
and System.Security.Cryptography
namespaces.
Console.ReadLine()
or Console.ReadKey()
methods, which asks you to enter the shared secret key and payload data.
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
// Set the shared secret key and payload data
string sharedSecretKey = "abcdef12-abcd-abcd-abcd-abcdef012345";
string payload = "{\"verification\":{\"callback\":\"https://veriff.com\",\"person\":{\"firstName\":\"John\",\"lastName\":\"Smith\"},\"document\":{\"type\":\"PASSPORT\",\"country\":\"EE\"},\"vendorData\":\"unique id of the end-user\",\"timestamp\":\"2016-05-19T08:30:25.597Z\"}}";
// Convert the shared secret key and payload to byte arrays
byte[] sharedSecretKeyBytes = Encoding.UTF8.GetBytes(sharedSecretKey);
byte[] payloadBytes = Encoding.UTF8.GetBytes(payload);
// Generate the HMAC-SHA256 hash using (var hmac = new HMACSHA256(sharedSecretKeyBytes))
{
byte[] hash = hmac.ComputeHash(payloadBytes);
// Convert the hash to a hexadecimal string
string xHmacSignature = BitConverter.ToString(hash).Replace("-", "").ToLower();
Console.WriteLine(xHmacSignature);
}
}
}
First set the shared secret key and payload data as
strings
.Next, convert them to byte arrays using the
Encoding.UTF8.GetBytes()
method.Then generate the HMAC-SHA256 hash using the
HMACSHA256
class, passing in the shared secret key bytes as the key and the payload bytes as the data to be hashed. The result is the hash value as a byte array.Convert it to a hexadecimal string using the
BitConverter.ToString()
method. Remove the hyphens using theReplace()
method, and convert the string to lowercase using theToLower()
method to obtain theX-HMAC-SIGNATURE
.Finally, write the
X-HMAC-SIGNATURE
to the console using theConsole.WriteLine()
method.
PHP example
This is an example of a script that generates an X-HMAC-SIGNATURE using only the built-in hash_hmac()
and strtolower()
functions.
$sharedSecretKey = 'abcdef12-abcd-abcd-abcd-abcdef012345';
$payload = '{"verification":{"callback":"https://veriff.com","person":{"firstName":"John","lastName":"Smith"},"document":{"type":"PASSPORT","country":"EE"},"vendorData":"unique id of the end-user","timestamp":"2016-05-19T08:30:25.597Z"}}';
$signature = hash_hmac('sha256', $payload, $sharedSecretKey);
$signature = strtolower($signature);
echo "X-HMAC-SIGNATURE: " . $signature . PHP_EOL;
Define the shared secret key and the payload as strings.
Generate the HMAC-SHA256 signature by calling the
hash_hmac()
function, passing the hashing algorithm ('sha256'), the payload, and the shared secret key.Then, convert the signature to lowercase using the
strtolower()
function.Finally, echo the
X-HMAC-SIGNATURE
to the output using theecho
statement.
Command-line tools
openssl example
This is an example of how to create the signature using openssl command-line tool.
In order to avoid hardcoding the shared secret key and the payload into your script or command and thus keep it secure and prevent accidental disclosure and misuse, we have saved the two values to separate files: secret_key.txt
and payload.tx
t.
set /p secret_key=<secret_key.txt && set /p payload=<payload.txt && echo | set /p dummy="%payload%" | openssl dgst -sha256 -hmac "%secret_key%" -hex
Open the command-line tool and navigate to the folder where the .txt files are.
Then, run the command above in the command prompt.
The
set /p
command is used to read the content of the files without adding a newline character. Theecho | set /p dummy=
part is used to output the content without a newline character.After running the command, you should get the HMAC signature as output.
Built-in crypto libraries
Python cryptographic library example
Most modern programming languages have built-in cryptographic libraries that provide functions for generating HMAC signatures.
Below is a general overview of how to use built-in cryptographic libraries to generate an HMAC signature:
Choose the SHA-256 cryptographic algorithm to generate signatures with Veriff.
Next, get the payload that you want to sign, and the shared secret key to generate the X-HMAC-SIGNATURE.
Once you have the payload and the shared secret key, initialize the HMAC function in the cryptographic library. This typically involves creating an HMAC object or specifying the algorithm and the secret key.
After initializing the HMAC function, update it with the payload you want to sign. This tells the function to incorporate the payload into the HMAC signature.
Finally, call a function in the cryptographic library to generate the HMAC signature based on the payload and secret key. This function should return the HMAC signature as a string or byte array, depending on the library and language you are using.
Here is an example of how you might generate an X-HMAC-SIGNATURE in Python using the built-in hmac
and hashlib
libraries:
import hmac
import hashlib
shared_secret_key = b'abcdef12-abcd-abcd-abcd-abcdef012345'
payload = b'{"verification":{"callback":"https://veriff.com","person":{"firstName":"John","lastName":"Smith"},"document":{"type":"PASSPORT","country":"EE"},"vendorData":"unique id of the end-user","timestamp":"2016-05-19T08:30:25.597Z"}}'
hash = hmac.new(shared_secret_key, payload, hashlib.sha256)
x_hmac_signature = 'sha256=' + hash.hexdigest()
print(x_hmac_signature)
The script imports the
hmac
library for generating the HMAC signature and thehashlib
library to access the SHA256 hashing algorithm.The shared secret key and payload are set as byte literals (strings with a
b
prefix) to ensure proper encoding for the HMAC calculation.The
hmac.new()
function takes three arguments to generates an HMAC hash:the shared secret key,
the payload, and
the hashing algorithm (in this case, SHA256 from the
hashlib
library)
The
hash.hexdigest()
method converts the HMAC hash into a hexadecimal string. The string'sha256='
is then prepended to the hexadecimal representation of the hash, creating the final X-HMAC-SIGNATUREThe X-HMAC-SIGNATURE is printed to the console.
Online tools
Use your favorite HMAC-SHA256 calculator to calculate the hash, e.g. Codebeautify HMAC Generator [↗]
Select SHA256 from the algorithm dropdown
Paste the shared secret key to the "Enter Key" field
Paste the appropriate payload to the "Enter the Plain or Cipher Text" field
Click on the Generate HMAC button
The result is a generated hash, which you can copy-paste to the X-HMAC-SIGNATURE in your API request
Headers
field.
Validate a signature locally
Below are few examples how to validate the generated X-HMAC-SIGNATURE. Click on the box to expand/collapse.
Do not use sensitive data or expose personally identifiable information (PII) even when testing.
Use Javascript isSignatureValid
function
isSignatureValid
functionThe purpose of the function is to validate that the provided signature is correct for the given payload and shared secret key. It does this by generating an X-HMAC-SIGNATURE of the payload using the shared secret key, and then comparing this HMAC to the provided signature.
Below is an example where we are using the mock shared secret key, signature and payload values. You can run this in a Node.js environment to validate the signature. To test a real signature, replace the mock values with real ones, but never expose PII when testing!
const crypto = require('crypto');
function isSignatureValid({ signature, shared_secret_key, payload }) {
if (payload.constructor === Object) {
payload = JSON.stringify(payload);
}
if (payload.constructor !== Buffer) {
payload = Buffer.from(payload, 'utf8');
}
const digest = crypto
.createHmac('sha256', shared_secret_key)
.update(Buffer.from(payload, 'utf8'))
.digest('hex')
.toLowerCase();
return digest === signature.toLowerCase();
}
const signature = "0dcab73ddd20062616d104231c7439657546a5c24e4691977da93bb854c31e25";
const shared_secret_key = "abcdef12-abcd-abcd-abcd-abcdef012345";
const payload = {
"verification": {
"callback": "https://veriff.com",
"person": {
"firstName": "John",
"lastName": "Smith"
},
"document": {
"type": "PASSPORT",
"country": "EE"
},
"vendorData": "unique id of the end-user",
"timestamp": "2016-05-19T08:30:25.597Z"
}
};
console.log(isSignatureValid({ signature, shared_secret_key, payload }));
If both match, the function returns true, indicating that the signature is valid, and the payload is likely to be authentic. If they don't match, it returns false, meaning the signature is invalid, and the payload's authenticity cannot be guaranteed.
Test the validation function in a local server
We recommend setting up a simple Express.js server in your local machine, to test the validation functionality independently of our webhook or API service.
Below is a simple Express.js server application written in JavaScript that listens for incoming POST requests to the /verification/ endpoint. The server validates the HMAC-SHA256 signature of the request payload using a shared secret key and responds with the validation status (true or false).
const express = require('express');
const bodyParser = require('body-parser');
const { createHmac } = require('crypto');
const { Server } = require('http');
const app = express();
const SERVICE_PORT = 3001;
const SECRET_KEY = 'abcdef12-abcd-abcd-abcd-abcdef012345';
function isSignatureValid({ signature, sharedSecretKey, payload }) {
if (payload.constructor === Object) {
payload = JSON.stringify(payload);
}
if (payload.constructor !== Buffer) {
payload = new Buffer.from(payload, 'utf8');
}
const digest = createHmac('sha256', sharedSecretKey)
.update(Buffer.from(payload, 'utf8'))
.digest('hex')
.toLowerCase();
return digest === signature.toLowerCase();
}
app.use(bodyParser.json());
let server = Server(app);
app.post('/verification/', (req, res) => {
res.json({
isSignatureValid: isSignatureValid({
signature: req.get('x-hmac-signature'), sharedSecretKey: SECRET_KEY, payload: req.body
})
});
})
server.listen(SERVICE_PORT, () => console.log('Server is UP \n Listening port:', SERVICE_PORT));
Now, post prepared data to the server you have set up:
curl --request POST "http://localhost:3001/verification/" -k --header "accept:application/json" --header "x-auth-client:abcdef12-abcd-abcd-abcd-abcdef012345" --header "x-hmac-signature:0dcab73ddd20062616d104231c7439657546a5c24e4691977da93bb854c31e25" --header "content-type:application/json" --data "{\"verification\":{\"callback\":\"https://veriff.com\",\"person\":{\"firstName\":\"John\",\"lastName\":\"Smith\"},\"document\":{\"type\":\"PASSPORT\",\"country\":\"EE\"},\"vendorData\":\"unique id of the end-user\",\"timestamp\":\"2016-05-19T08:30:25.597Z\"}}"
This curl above should return {"isSignatureValid":true}
Mock data to test signature generation locally
Beware the hardspaces: generating the value may vary depending on the programming language used, e.g., some languages include the hard spaces in the body, and some omit them.
Mock shared secret key:
abcdef12-abcd-abcd-abcd-abcdef012345
POST /sessions request mock payload (as .json):
{"verification":{"callback":"https://veriff.com","person":{"firstName":"John","lastName":"Smith"},"document":{"type":"PASSPORT","country":"EE"},"vendorData":"unique id of the end-user","timestamp":"2016-05-19T08:30:25.597Z"}}
To generate an actual signature for your live API requests, the Headers explanation in each API request’s section tells you what to use as payload for encryption.
If your preferred method is correct, you should get the following mock X-HMAC-SIGNATURE:
0dcab73ddd20062616d104231c7439657546a5c24e4691977da93bb854c31e25