I'm trying to setup a webhook listening endpoint using Flask. The listening is for ExLibris Alma.
https://developers.exlibrisgroup.com/alma/integrations/webhooks/anatomy/
I've got the endpoint able to respond to the initial challenge (GET). I can also detect the Webhook Event (POST).
I'm using the Thunder Client extension in VS Code to send the requests to my local Flask app (so it's all local)
What I can't quite figure out how to do is send a request with a signature using a shared secret. Following these details (from the page linked above)
Signature
The signature ensures the message came from Alma and that it was not tampered with​. It is recommended (but not required) that the listener validate the signature​. The signature is a Base64 encoded HMAC SHA256​ hash of the entire body payload and is sent in the X-Exl-Signature header. The shared secret is specified in the webhook integration profile.
I've got some basic code that can calculate a signature given the shared secret and a message
import base64
import hashlib
import hmac
import os
from dotenv import load_dotenv
load_dotenv()
ALMA_WEBHOOK_SECRET = os.getenv('ALMA_SECRET')
def calc_secret(secret, message):
'''
The signature is a Base64 encoded HMAC SHA256​ hash of the entire body payload and is sent
in the X-Exl-Signature header.
The shared secret is specified in the webhook integration profile.
'''
secret = bytes(secret, 'utf-8')
message = bytes(message, 'utf-8')
signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest())
return signature # This secret should match what's in the header
print(ALMA_WEBHOOK_SECRET)
msg_sig = calc_secret(ALMA_WEBHOOK_SECRET, 'hello world')
print(msg_sig)
But I can't figure out how to send a test message to my endpoint to make sure I'm processing and comparing the correct values.
Hope all that makes sense? I will try to clarify if not. 🙂
The following describes the pieces that make up an Alma webhook listener. Challenge (GET) When registering a webhook listener as an integration profile, Alma “challenges” the listener. This ensures an active listener is available at the provided URI​. The listener should reply to the GET request with the challenge sent in the querystring​. Alma ...