Morta by default will sign every webhook with a signature in the Morta-Signature
header. This allows you to verify that webhook data is from Morta, and the data has not been tampered with.
Before you can verify signatures, you'll need to retrieve your signing secret for the project. This will located in your Project -> Settings -> Developer page.
The Morta signature includes two pieces of information, the timestamp of the event, and HMAC of the body of the POST request.
The signature header is formatted as:
Morta-Signature: t=1234567890,v1=5ab0811a0d362f7becff116ce7b232c3ef61400d01911c50c03183a44d4cb00c
The timestamp is prefixed with t=
and the signature is prefixed with v1=
. The signature is generated using HMAC with SHA256 digest.
Pull out the timestamp and the signature from the header.
The signature is based on concatenating:
.
Using the message created above, use HMAC with SHA256 and your secret signing key to generate the signature.
Finally compare the signature you've generated with the signature that is present in the request. If they are equal, you've verified that the webhook is valid.
Here is sample code to verify the signature using Python and the Flask web framework
import hmac
from flask import Flask, request, abort
app = Flask("example")
@app.route("/webhook", methods=["POST"])
def index():
body = request.data.decode("utf8")
signing_secret = bytes("YourSigningSecret", "utf8")
sig_header = request.headers["Morta-Signature"]
ts_kv, sig_kv = sig_header.split(",")
ts = ts_kv.split("=")[1]
sig = sig_kv.split("=")[1]
message = bytes(f"{ts}.{body}", "utf8")
h = hmac.new(signing_secret, message, digestmod="sha256")
valid = hmac.compare_digest(h.hexdigest(), sig)
if not valid:
abort(400, "Signature is not valid")
return "OK"
app.run(host="0.0.0.0", port=4500, debug=True)