Integrating a secret token with your webhook is important to confirm that the requests are indeed coming from Uplift. Creating and adding this secret is easy:
Navigate to Create Webhook modal.
While creating a webhook, provide a secret token along with other webhook details.
The secret token should be set as a random string with high entropy:
Ruby:
ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'
Python:
import os, binascii; print(binascii.hexlify(os.urandom(20)))
Node:
require('crypto').randomBytes(20).toString('hex');
Click
Create
to create the webhook.Ensure that you store the secret token provided while creating of webhook safely and store it in the environment variable of your server for validation of payloads from Uplift.
Never hardcode the secret token into your app!
Validating payloads from Uplift
Once you set a secret token, Uplift uses the token to create a hash signature for each payload and sends it via the x-uplift-signature-256
header.
Now the intention is to calculate a hash using your secret token and then compare it to the hash provided by Uplift. You'll successfully validate that the payload was sent by Uplift if you find the hash calculated by you to be the same as the hash sent by Uplift.
Here are some sample verify_signature
functions in different languages:
Python:
import os
import hmac
import hashlib
def verify_signature(request_body, signature_from_request_header):
calculated_signature = 'sha256=' + hmac.new(bytes(os.environ['SECRET_TOKEN'], encoding='utf-8'), request_body.encode('utf-8'), hashlib.sha256).hexdigest()
return hmac.compare_digest(calculated_signature, signature_from_request_header)
Node:
const crypto = require('crypto');
const verify_signature = (request_body, signature_from_request_header) => {
return crypto.timingSafeEqual(Buffer.from(signature_from_request_header), Buffer.from('sha256=' + crypto.createHmac('sha256', process.env.SECRET_TOKEN).update(request_body).digest('hex')))
}
Ruby:
def verify_signature(request_body, signature_from_request_header)
calculated_signature = 'sha256=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), ENV['SECRET_TOKEN'], request_body)
return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, signature_from_request_header)
end
Uplift uses an HMAC hex digest to compute the hash. You could set up a verify_signature
to calculate the hash and verify it with the hash provided by Uplift in the x-uplift-signature-256
header.
Your language and server implementations may differ from the example code provided above. However, there are some important things to point out:
No matter which implementation you use, the hash signature starts with
sha256=
, using the key of your secret token and the payload body.Using a plain
==
operator is not advised. A method likecompare_digest
/timingSafeEqual
/secure_compare
performs a "constant time" string comparison, which helps mitigate timing attacks against regular equality operators.
If you need any more assistance setting up Uplift's Secret Token for validating Webhooks requests, please contact your support representative.