Webhook Secrets

Setting Up a Secret Token to Validate Webhooks Requests from Uplift

Jonathan Wills avatar
Written by Jonathan Wills
Updated over a week ago

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:

  1. Navigate to Create Webhook modal.

  2. While creating a webhook, provide a secret token along with other webhook details.

  3. The secret token should be set as a random string with high entropy:

    1. Ruby: ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'

    2. Python: import os, binascii; print(binascii.hexlify(os.urandom(20)))

    3. Node: require('crypto').randomBytes(20).toString('hex');

  4. Click Create to create the webhook.

  5. 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.

  6. 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:

  1. No matter which implementation you use, the hash signature starts with sha256=, using the key of your secret token and the payload body.

  2. Using a plain == operator is not advised. A method like compare_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.

Did this answer your question?