Skip to content

Verifying webhook signatures

To prevent third parties from impersonating AuthRamp to your application, verify that each payload sent to your application came from AuthRamp by inspecting its HMAC signature. Every time AuthRamp POSTs to your application, an HTTP header, X-Authramp-Signature, is sent along with the content. It will contain an HMAC+SHA256 signature of the HTTP body payload.

Find your hmac signing key

Find your app's unqiue signing key on the Webhook Config page on AuthRamp.

You can generate a new HMAC signing key at any time, but you must use the new key immediately in your own app to avoid rejected webhook calls.

Generating HMAC Secret

Verifying signatures

Included in each POST request AuthRamp sends to your servers, there will be a X-Authramp-Signature header with a HMAC (SHA-512 digest) that should be validated against the body of the request.

Using secure comparison operators

Do not use a plain equality operator (==) to compare signatures. Doing so will leave your application vulnerable to a timing attack. Instead, use your language's secure comparison function for a seucre verification of the signature.

Example Code

Use Python's hmac module and the compare_digest function from the secrets module.

import hashlib
import hmac
from secrets import compare_digest

import flask
from flask import Flask, request, Response

app = Flask(__name__)

# Get the secret key from AuthRamp -> Settings -> Webhooks
WEBHOOK_SECRET_KEY = "YOUR SECRET KEY".encode("ascii")


def verify_signature():
    received_sign = request.headers.get('X-Authramp-Signature').strip()
    expected_sign = hmac.new(WEBHOOK_SECRET_KEY, request.data, digestmod=hashlib.sha512).hexdigest()
    if not compare_digest(received_sign, expected_sign):
        flask.abort(400)


@app.route("/authramp-webhook/", methods=['POST'])
def test_webhook():
    verify_signature()

    # Request is legitimate
    return Response("All is good", mimetype='text/plain')

Be sure to use Rack::Utils.secure_compare to compare the signature:

# Get the secret key from AuthRamp -> Settings -> Webhooks
WEBHOOK_SECRET_KEY = "YOUR SECRET KEY"


def verify_signature(payload, signature)
    Rack::Utils.secure_compare(
        Base64.encode64(
            OpenSSL::HMAC.digest(
                OpenSSL::Digest::Digest.new('sha512'), SHARED_SECRET, payload
            )
        ).strip,
        signature)
end

def webhook_access
    verified = verify_signature(request.body.read, 
                               request.headers["X-Authramp-Signature"])
    if verified
        return
    else
        render nothing: true, status: :unauthorized
    end
end