Andre Bulatov Andre Bulatov - 1 year ago 54
JSON Question

Encoding PHP POST response's JSON body into HMAC SHA256, and then into Base64

How to receive raw JSON response from HTTP POST webhook?

I am working with an API and to verify that the POST to the webhook is indeed from the appropriate company API, they suggest this method:

To allow a client to verify a webhook message has in fact come from SIGNIFYD, an X-SIGNIFYD-SEC-HMAC-SHA256 header is included in each webhook POST message. The contents of this header is the Base64 encoded output of the HMAC SHA256 encoding of the JSON body of the message, using the team's API key as the encryption key. To verify the authenticity of the webhook message, you should calculate this value yourself and verify it equals the value contained in the header.

For the test environment, the "secret" key is
instead of the "Team API key."

I am receiving it in PHP like so:


// Get relevant Signifyd custom headers to be used for verification
$header_sig_topic = $_SERVER['HTTP_X_SIGNIFYD_TOPIC'];
$header_sig_sec_hmac = $_SERVER['HTTP_X_SIGNIFYD_SEC_HMAC_SHA256'];

// Get POST body
$webhookContent = "";
$webhook = fopen('php://input' , 'r');
while (!feof($webhook)) {
$webhookContent .= fread($webhook, 4096);


then I am processing it into the hash like so:

$sig_ver_sha = hash_hmac('sha256', $webhookContent, $secret);
$sig_ver_hash = base64_encode( $sig_ver_sha );

However, I am going wrong somewhere, because the hash I calculate is


while the header for an identical sample response header always comes with


I thought I was getting the JSOn body wrong somehow so I've tried every combination of json_encode and json_decode but nothing helps, my hash never matches.

I've also tried using
$webhookContent = json_decode(file_get_contents('php://input'), true);
to store the POST body but that just comes up empty ($_POST doesn't work either).

Am I doing something else wrong other than receiving the JSON?

The JSON that comes as the body of the test response which always comes with
as the hash key to be used for verification:

{ "analysisUrl": "",
"entriesUrl": "", "notesUrl":
"", "orderUrl":
"", "guaranteeEligible":false,
"status":"DISMISSED", "uuid":"709b9107-eda0-4cdd-bdac-a82f51a8a3f3",
"headline":"John Smith", "reviewDisposition":null, "associatedTeam":{
"teamName":"anyTeam", "teamId":26, "getAutoDismiss":true,
"getTeamDismissalDays":2 }, "orderId":"19418",
"orderDate":"2013-06-17T06:20:47-0700", "orderAmount":365.99,
"adjustedScore":262.6666666666667, "investigationId":1,
"score":262.6666666666667, "caseId":1,

If it helps to see where I'm going wrong, an example is provided but it's in Python:

Mac sha256HMAC = javax.crypto.Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(teamAPIKEY.getBytes(), "HmacSHA256");
String encodedHMAC256 = Base64.encodeBase64String(sha256HMAC.doFinal(jsonBody.getBytes("UTF-8")));


My error was in simply not specifying the $raw_output parameter of the hash_hmac() function as true.

When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.

So, since I wasn't specifying $raw_output as true, I was getting hexits instead of raw binary output, which looked like this: 975c11d66e1515fbbf5ca44a5c1db3d946c78a84567bda2fd2eab484a69a57bb.