# HMAC verification with PHP

\
\
Ivan Dinkov Sr. Developer Support Advisory Engineer

---

Summary•3 min read

Learn how to secure your Docusign Connect webhook calls with HMAC verification

## **The problem: Testing your HMAC verification code**

Regardless of your listener implementation, whether [Platform-as-a-Service](https://www.infoworld.com/article/3223434/what-is-paas-software-development-in-the-cloud.html) (PaaS) as suggested in [Building best practices webhook listeners, part 4](https://www.docusign.com/blog/dsdev-webhook-listeners-part-4) or a custom listener, you face the issue of constantly resending envelopes while you test your application.

The PHP sample code below verifies the HMAC signature sent in the header of the notification message. To test the code on your localhost development machine, use the Postman [replaying webhook messages technique](https://www.docusign.com/blog/developers/replaying-webhook-messages-postman).

Note that the HMAC hash should be verified **before** the request body is parsed. The request body is **untrusted** until the HMAC hash is verified.

## **Example: Checking the HMAC signature using vanilla PHP**

```php
<?php // Copyright (c) 2020 Docusign Inc. MIT License https://opensource.org/licenses/MIT
// save this file as index.php in your web server root folder
// enable only in development
eerror_reporting(E_ALL);
ini_set('display_errors', 1);

$secret = "your secret key";// your secret key
$payload = "";// request body
$headers = "";// request message headers array

$signature = "";// the HMAC hash key in the HTTP header x-docusign-signature-1
$result = false;// verification result

if (isset($_POST)) {
    try {
        $payload = file_get_contents('php://input');
        $headers = get_ds_headers();
        if (array_key_exists("XDocusignSignature1", $headers)) {
            $signature = $headers["XDocusignSignature1"];
            $result = hash_is_valid($secret, $payload, $signature);
            log_result($signature, $payload, $result);
        }
    } catch (Exception $e) {
        logger("\nException: " . $e->getMessage() . "\n");
    }
    header("HTTP/1.1 200 OK");
}

function get_ds_headers()
{
    $headers = array();
    foreach ($_SERVER as $key => $value) {
        if (strpos($key, 'HTTP_') === 0) {
            $headers[str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower(substr($key, 5)))))] = $value;
        }
    }
    return $headers;
}

function compute_hash($secret, $payload)
{
    $hexHash = hash_hmac('sha256', $payload, utf8_encode($secret));
    $base64Hash = base64_encode(hex2bin($hexHash));
    return $base64Hash;
}

function hash_is_valid($secret, $payload, $verify)
{
    $computed_hash = compute_hash($secret, $payload);
    return hash_equals($verify,$computed_hash);
}

function log_result($signature, $payload, $result)
{
    $result_to_log = $result == 1 ? "pass" : "fail";
    if ($result) {
        try {
            $xml = simplexml_load_string($payload);
            $envelopeId = $xml->EnvelopeStatus->EnvelopeID;
            $status = $xml->EnvelopeStatus->Status;
            $created = $xml->EnvelopeStatus->Created;
        } catch (Exception $e) {
            logger("\nException: " . $e->getMessage() . "\n");
        }
        logger("\n");
        logger("EnvelopeID: " . $envelopeId);
        logger("Signature: " . $signature);
        logger("HMAC check status: " . $result_to_log);
        logger("Envelope Status: " . $status);
        logger("Generated at: " . $created);
    } else {
        logger("\n");
        logger("HMAC check status: " . $result_to_log);
        logger("Generated at: " . date('Y-m-d H:i:s')); 
    }
}

function logger($txt)
{
    $log_file = "log.txt";
    $myfile = fopen($log_file, "a") or die("Unable to open file!");
    fwrite($myfile, "\n" . $txt);
    fclose($myfile);
}
?>
```

## **Summary**

By using the Postman replay technique, you can test your HMAC verification implementation in your local environment.

## **Additional resources**

- [Docusign Developer Center](https://developers.docusign.com/)

- [Docusign for Developers on LinkedIn](https://www.linkedin.com/showcase/docusign-for-developers/)

- [Docusign Developer Newsletter](https://developers.docusign.com/#newsletter-signup)

Ivan Dinkov Sr. Developer Support Advisory Engineer
