Verify Webhook Signature
Verify the events that Elements send to your webhook endpoints to avoid any unusual traffic to the endpoint.
Retrieve webhook signing secret
Before you can verify signature, go to Elements Merchant console to retrieve the webhook secrets, you will need to use the secret verify webhook events.


Verify the signature
Below is a webhook example
curl --location --request POST '<Your endpoint receive the webhook>' \
--header 'timestamp: 1650410593' \
--header 'signature: ngp+k/e0RuHY7fS9OeWFTfr1Wlh53rv87tCjqTwxWHg=' \
--header 'Content-Type: application/json' \
--data-raw '{
"id": "CH-RSZ8dyzAmZHFGJ8m1XNDqRaX",
"type": "charge",
"status": "failed",
"amount_subunit": 12345,
"captured_amount_subunit": 12345,
"currency": "USD",
"metadata": null,
"captured": true,
"description": "test data",
"created_at": 1621816399,
"refunded": false,
"disputed": true,
"reference_id": null,
"funding_source": null,
"funding_source_details": {
"expiration_month": null,
"expiration_year": null
},
"psp_source_details": {
"name": "StripeGateway"
}
}'
Get the data used for verification - Get the timestamp
value from webhook request header and raw request body json
, concat them to a string.
timestamp = request.headers[:timestamp]
raw_request_body = JSON.parse(request.body.read)
data_for_hmac_verify = "#{timestamp}.#{raw_request_body.to_json}"
Calculate an HMAC using:
- The SHA256 function.
- Binary representation of the
data_for_hmac_verify
, given the UTF-8 charset. - Binary representation of the HMAC key, given the UTF-8 charset.
- To get the final signature, Base64-encode the result.
raw_request_body = JSON.parse(request.body.read)
timestamp = request.headers[:timestamp]
signature = request.headers[:signature]
data_for_hmac_verify = "#{timestamp}.#{raw_request_body.to_json}"
calculated_hmac = Util::Hmac.calculate(
webhook_signing_secret,
data_for_hmac_verify,
)
## Util class to calculate HMAC value
module Util
class Hmac
DIGEST = OpenSSL::Digest.new('sha256')
def self.calculate(key, data)
hmac_key_hex = string_to_hex(key)
hex = OpenSSL::HMAC.digest(DIGEST, hmac_key_hex, data)
base64_encode(hex)
end
def self.string_to_hex(string)
Array(string).pack('H*')
end
def self.base64_encode(string)
Base64.strict_encode64 string
end
end
end
Compare with the signature
If the signature that you calculated above matches the signature from request header, you can confirm that the notification was sent by Elements and was not modified during transmission.
Updated 2 months ago