Axle Health currently supports two types of authentication for webhooks.

Authentication Tokens

We can set api keys of your choice in the Authentication header of our requests. Currently supported authentication schemes currently include:

  1. Basic Authentication
  2. Bearer Tokens

If you would like to use another token based authentication token method, please reach out to the Axle team for support.

Webhook Signature

Axle Health optionally supports sending signed webhook signatures in the Axle-Signature HTTP header. You can verify this signature manually to ensure that the webhook was not sent by an un-authorized third party.

Steps to Verify Signature

Step 1: Extract timestamp and signature from Axle-Signature

Both the timestamp and the signed signature are included in the Axle-Signature header.

Example:Axle-Signature: t=<UNIX_TIMESTAMP_IN_SECONDS>,v1=<SIGNATURE>

Step 2: Generate the expected signature

To generate the signature, create an HMAC using SHA-256. The key to use is the key provided by Axle Health. The message format for use in the HMAC is as follows:

message = <UNIX_TIMESTAMP_IN_SECONDS>.<HTTP_BODY_AS_STRING>

Step 3: Verify the signature

If your generated signature is the same as the signature retrieved from the Axle-Signature header, then you have successfully verified the authenticity of the received webhook.

Security Notes

There are two attack vectors to be aware of and to guard against when using webhook signatures.

Timing Attacks:
To guard against timing attacks, it is advised that you use a constant time comparison function when comparing your generated signature to the signature sent in the Axle-Signature header.

Replay Attacks
Replay attacks can happen when an attacker intercepts webhooks sent to you and resends it to you at a different time. To guard against this, the timestamp is included in the webhook signature so that the timestamp cannot be changed without invalidating the signature. As is required by your own security needs, you can choose a tolerance window in which you will accept incoming webhooks.

Code Samples

import hmac
from hashlib import sha256
from rest_framework.response import Response

webhook_secret = '<WEBHOOK_SECRET_KEY>'

def webhook_handler(request):
    timestamp, signature = get_timestamp_and_signatures(request.META['HTTP_AXLE_SIGNATURE'])
    body = request.body.decode('utf-8')
    message = f'%{timestamp}.{body}'
    gen_signature = generate_signature(
        webhook_secret, 
        message
    )

    if hmac.compare_digest(signature, gen_signature):
        # Your Logic here
        return Response()
    else:
        # Raise exception and handle error
        return Response(status=403)

def generate_signature(key, message):
    mac = hmac.new(
        key.encode('utf-8'), 
        msg=message.encode('utf-8'), 
        digestmod=sha256
    )
    return mac.hexdigest()

def get_timestamp_and_signatures(header):
    (t, signature) = header.split(',')
    t = t.split('=')[1]
    signature = signature.split('=')[1]
    return t, signature