HMAC (Hash-based Message Authentication Code)

HMAC for webhooks can be calculated using SHA256 and SHA512 algorithms combined with the data and the key. You can also use MD5, SHA1 but those methods are no longer recommended.

It may be used to simultaneously verify both the data integrity and the authenticity of a message. In this example we will use GitHub webhooks. Other providers that use HMAC authentication:

While this example is using GitHub, the same approach can be used for other providers. You will only need to modify two lines of the function when using other providers:

  1. local signature_header = 'X-Hub-Signature-256' will need to include your provider’s header name
  2. if "sha256=" .. calculated_hmac ~= r.RequestHeader[signature_header] then you might need to change the prefix sha256= to something else or remove it completely based on your provider docs

Create Function

Go to the Functions page and create a new Function with the given code:

local crypto = require('crypto')

-- Header name that contains HMAC signature
local signature_header = 'X-Hub-Signature-256'

-- Calculate HMAC of the request body using SHA256
local calculated_hmac, err = crypto.hmac(
    'sha256',
    r.RequestBody,
    cfg:GetValue("WEBHOOK_SECRET"))
if err then error(err) end

-- Check whether calculated HMAC matches the one that was sent
-- with the message. Adding the prefix "sha256=" as our signature
-- that is coming from GitHub will have it.
if "sha256=" .. calculated_hmac ~= r.RequestHeader[signature_header] then
    r:SetResponseStatusCode(401)
    r:SetResponseBody("Authentication failure: " .. calculated_hmac)
    r:StopForwarding()
    return
end

r:SetResponseBody("OK")

Once created, click on “config variables” and add the WEBHOOK_SECRET which is used to sign the webhook requests:

webhook secret setting

and then enter the same secret in the webhook provider. For this example I will be using GitHub:

github secret setting

Once webhook is added, GitHub will send a test payload.

Testing HMAC verification

You can take the payload from GitHub events page and copy paste it into the Function composer together with the X-Hub-Signature-256 header:

HMAC verification success

Testing HMAC failure case

HMAC works by computed hash of the body and the secret key. If you edit the request body by just adding some letters and retry, HMAC verification will fail:

HMAC verification failure