--- title: "HMAC Authentication and Endpoint Security | Veriff.com" slug: "hmac-authentication-and-endpoint-security" description: "Implement secure API and webhook communication with HMAC signatures." status: "update" updated: 2026-05-22T12:19:15Z published: 2026-05-22T12:19:22Z canonical: "devdocs.veriff.com/hmac-authentication-and-endpoint-security" --- > ## Documentation Index > Fetch the complete documentation index at: https://devdocs.veriff.com/llms.txt > Use this file to discover all available pages before exploring further. # HMAC Authentication and Endpoint Security 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 HMAC-SIGNATURES (as `x-hmac-signature` header or `VRF-HMAC-SIGNATURE` header) and allowed IP lists and ranges for that purpose. ## What must be signed? **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. ### Public API v1 Uses the **X-HMAC-SIGNATURE header.** As a rule of thumb: - **POST / PATCH** endpoints require you sign the **request payload body** - **GET / DELETE** endpoints require you sign the session ID > [!NOTE] > Exception is [POST /sessions](https://veriff-dev-documentation.document360.io/apidocs/v1sessions) endpoint (used to generate a session) which does not require the **X-HMAC-SIGNATURE header.** If unsure, then each API endpoint's documentation describes what you need to sign to create the signature. Navigate to [Veriff Public API v1 documentation](https://devdocs.veriff.com/apidocs/public-api-1) > required endpoint for more info. ### Feedback API Uses the **VRF-HMAC-SIGNATURE header.** As a rule of thumb: - **POST** endpoints require you sign the **full request path and request payload body**. There **must be a new line breaker** between the endpoint URL and the payload body (`\n` or any alternative logic in other programming language) - **GET** endpoints require you sign the **full request path** Each API endpoint's documentation describes what you need to sign to create the signature. Navigate to [Feedback API documentation](/v1-api/apidocs/fraud-1) for more info. ### Webhooks Uses the **X-HMAC-SIGNATURE header.** For webhooks, the `raw body` of the request is signed (for troubleshooting purposes, you can find a webhook’s `raw body` in Veriff Customer Portal > Verifications > *session view* > Webhooks tab). *→ Go to* [*Webhooks*](/v1/docs/webhooks-guide) *docs* --- ## Prerequisites If you want to generate a 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*](/v1/docs/hmac-authentication-and-endpoint-security#mock-data-to-test-signature-generation-locally) *to test signature generation or validation in your local machine* ## Generate a 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**. ⚠️ Note that you may need to add this module. ```javascript 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); ``` 1. 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 2. Next, prepare the payload data and generate the HMAC-SHA256 hash: 1. Use the `crypto.createHmac()` method, which takes the algorithm name ("sha256") and the shared secret key as arguments, and returns an HMAC object 2. Call the `update()` method of the HMAC object with the payload data to update the HMAC with the payload data 3. Then, call the `digest()` method with the argument "hex" to obtain the hash value in hexadecimal format 3. Store the X-HMAC-SIGNATURE and output it: 1. Store the hash value directly in the `xHmacSignature` variable 2. Finally, 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**. ⚠️ In this example, the shared secret key and the payload are hardcoded. If you think that **you do not want to hardcode** them, one option is to create a prompt using the `Console.ReadLine() `or` Console.ReadKey()` methods, which asks you to enter the shared secret key and payload data. ```csharp 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);            }    } } ``` 1. First set the shared secret key and payload data as `strings`. 2. Next, convert them to byte arrays using the `Encoding.UTF8.GetBytes()` method. 3. 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. 4. Convert it to a hexadecimal string using the `BitConverter.ToString()` method. Remove the hyphens using the `Replace()` method, and convert the string to lowercase using the `ToLower() `method to obtain the `X-HMAC-SIGNATURE`. 5. Finally, write the `X-HMAC-SIGNATURE` to the console using the `Console.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**. ```php $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;             ``` 1. **Define** the **shared secret key** and the **payload** as **strings**. 2. **Generate** the HMAC-SHA256 **signature** by calling the `hash_hmac()` function, **passing the hashing algorithm** ('sha256'), the **payload**, and the **shared secret key**. 3. Then, **convert** the signature to **lowercase** using the `strtolower()` function. 4. Finally, e**cho the** `X-HMAC-SIGNATURE` to the **output** using the `echo` 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. ```batch set /p secret_key= {    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 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 > [!WARNING] > **Beware the hardspace**s: 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. 1. Mock shared secret key: ```plaintext abcdef12-abcd-abcd-abcd-abcdef012345 ``` 2. POST /sessions request **mock payload** (as .json): ```plaintext {"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. 1. If your preferred method is correct, you should get the following **mock X-HMAC-SIGNATURE**: ```plaintext 0dcab73ddd20062616d104231c7439657546a5c24e4691977da93bb854c31e25 ``` --- ## Validate webhook’s `x-hmac-signature` header value If you want to validate Veriff webhook’s `x-hmac-signature` header value, follow these steps: 1. Have your integration’s shared secret key at hand 2. Have your preferred hmac signature generation tool at hand 3. Go to Veriff Customer Portal and navigate to the session’s page 4. Click the session’s **Webhook** tab 5. Select the webhook and click on **Details** 6. Copy the payload from **Raw body** box ![](https://cdn.document360.io/5c26138b-b1e9-404e-a2e4-c83a49245be7/Images/Documentation/image(6).png) 7. Use the payload and the shared secret key to calculate the `x-hmac-signature` 8. Calculated value should match with the `x-hmac-signature` header value shown in **Details** > **Request headers** box ![](https://cdn.document360.io/5c26138b-b1e9-404e-a2e4-c83a49245be7/Images/Documentation/image(5).png) > [!WARNING] > Ensure that you use the **raw body** payload, otherwise the values may not match. --- ## Changelog | Date | Description | | --- | --- | | May 22, 2026 | Updated [Public API v1](/v1/docs/hmac-authentication-and-endpoint-security#public-api-v1) section with an exception notice | | Mar 5, 2026 | Wording directing to API Documentation and Reference updated | | Dec 19, 2025 | New section [What must be signed?](/v1/docs/hmac-authentication-and-endpoint-security#what-must-be-signed) added to give more details about what elements need to be signed to generate hmac-signature | | Sep 3, 2025 | [Validate webhook's x-hmac-signature header value](/v1/docs/hmac-authentication-and-endpoint-security#validate-webhooks-xhmacsignature-header-value) section added | | Jul 11, 2025 | Note about webhooks signing added | | Mar 12, 2025 | Documentation published | A **message** sent to a server **asking for the API to provide service or information**. Also referred to as the **API call**. A webhook listener is an endpoint in a web application or service that waits for and receives HTTP requests from other web applications or services. It listens for incoming HTTP requests sent by other applications when certain events occur. The webhook listener parses a request sent by a source application at a certain trigger event, extracts the relevant data, and takes appropriate actions based on the content of the message. These actions are specific to the application or service. A **unique identifier of a verification session**. It is automatically created as soon as you create a session. In the **API requests' context**, one verification session comprises many steps (uploading data, uploading images, getting a decision, etc.). You can call several endpoints using the same **session ID**, to get all kinds of different data from that specific session. You can find its value in the **response payload** of your **POST /sessions API request**, in the `verification.id` parameter. Veriff customer back-office, a dashboard where you can see your end-users' verification data. Depending on your setup, you may be required to access the environment via station.veriff.com or hub.veriff.com. Always **check your sign-up email** and make sure that you **log in via correct address**. A **unique identifier of an integration.** A **required parameter for authentication: i**t is used to create the `X-AUTH-CLIENT header` value for **API requests**. Occasionally, referred to as the "API public key" or "Publishable key". You can find it in **Veriff Customer Portal** > **API keys** page (you need to be logged in). **Mandatory parameter for authentication**, used to **sign the payload to create the X-HMAC-SIGNATURE** for API requests. This is a **secret credential**. You can find it in **Veriff Customer Portal** > **Integration** tab (you need to be logged in). Occasionally, referred to as the "API private key" or the "Private key". The data that you send when you make an API request, or that you receive when you get a response. Indicates the **media type of the resource.** In Veriff's context, usually "application/json". A specific “point of entry” in an API. For **webhooks**, this is the point of entry on your side. For **Veriff public API**, you need to attach an endpoint to the end of your `baseURL` to complete the **API URL**. The results that you will get from the Veriff public API request will depend on the endpoint you attach. **Mandatory elements** in the **API requests**, containing the metadata. ## Related - [Webhooks Guide](/webhooks-guide.md)