Handle Deliveries
This article provides code example to receive and process Webhook messages on your server, and send a response to the Mist Cloud to confirm the delivery.
In order to handle webhook deliveries, your Webhook collector must:
- Listen for Incoming Webhooks: The collector should listen for incoming HTTP POST requests from the Mist Cloud.
- Validate Signature: (Optional) Validate the signature sent by the Mist Cloud using the secret key.
- Process Payload: Once validated, process the payload (JSON) and take desired actions.
- Send Response: Send a successful response (HTTP 200) to the Mist Cloud to confirm delivery.
The following code samples are examples to quickly start with Mist Webhooks. They will:
- Listen for incoming webhook messages on port TCP3000
- Check the Webhook Signature
- If the signature matches the secret, print the webhook payload on the console and respond with a HTTP200 to the Mist Cloud
- If the signature doesn't match the secret, print an error message on the console and response with a HTTP401 to the Mist Cloud
Notes:
Make sure to replace the placeholder values (
SECRETandSERVER_PORTfor the Python sample,secretandserver_portfor the JavaScript one) with your actual secret key and desired port number. For the Python code, ensure you have Flask installed (pip install flask). For the JavaScript code, ensure you have ExpressJS (npm i express) and body-parser (npm i body-parser) installed.
These examples are designed to be a starting point for your webhook collector. You can customize them as per your specific requirements and integrate with your existing system or services.
Python code sample
This code sample is using Python Flask to collect the Webhook messages. See Python Flask Installation for more information.
The provided Python code sample uses Flask for creating an HTTP server that listens on port 3000. It sets up a POST operation decorator for the webhook collector and defines the operation function. Inside this function, it checks if the secret is defined and validates the signature using HMAC with SHA256.
# import `Flask` (Web Server)
from flask import Flask, request
# import crypto dependencies to validate the webhook signature
import hmac
import hashlib
# define script variables:
# - SECRET: Webhook secret, used to validate the webhook signature
# - SERVER port: port used by Flask to listen for incoming messages
SECRET = ""
SERVER_PORT = 3000
# create a Flask instance
app = Flask(__name__)
# create a POST operation decorator for the webhook collector, and
# define the webhook collector path to "/collector"
@app.post("/collector")
# define the operation function
def webhookCollector():
# print a message to notify when there is a new message
print(" New message reveived ".center(60, "-"))
# if the SECRET variable is defined, try to validate the webhook signature
if SECRET:
# retrieve the signature from the HTTP Headers
signature = (
request.headers["X-Mist-Signature-v2"]
if "X-Mist-Signature-v2" in request.headers
else None
)
# calculate the expexted signature based on
# - the configured value of the SECRET variable
# - the Webhook body content
key = str.encode(SECRET)
message = request.data
digester = hmac.new(key, message, hashlib.sha256).hexdigest()
# if the received signature doesn't match the calculated one, stop
# the processing and send a HTTP401 response
if signature != digester:
print("Webhook signature doesn't match")
print(f"Received signature: {signature}")
print(f"Calculated signature: {digester}")
return "", 401
# otherwise (the signature matches), continue the processing of the payload
else:
print("Webhook signature confirmed")
# retrieve the webhook body as a JSON object
content = request.get_json()
# print the JSON object
print(f"Webhook content: {content}")
# send a HTTP200 response
return "", 200
# start the FLASK Server using the SERVER_PORT variable defined above.
# the server will listen on this specific port
if __name__ == "__main__":
print(f"Starting Server: 0.0.0.0:{SERVER_PORT}")
app.run(debug=False, host="0.0.0.0", port=SERVER_PORT)
JavaScript code sample
This code sample is using ExpressJS to collect the Webhook messages and Bodsy-Parser for the signature validation. See ExpressJS Installation and body-parser installation for more information.
The JavaScript code sample utilizes ExpressJS to create an HTTP server listening on port 3000. The server uses body-parser to parse JSON bodies of incoming requests. It also sets up a POST route for the webhook collector. Inside this route, it verifies the request signature before processing the payload using HMAC with SHA256.
// import `express` library (web server)
import express from 'express';
import bodyParser from 'body-parser';
// import crypto dependencies to validate the webhook signature
import * as crypto from 'crypto';
// define script variables:
// - secret: Webhook secret, used to validate the webhook signature
// - server port: port used by Flask to listen for incoming messages
const secret = "";
const server_port = 3000;
// Initialize a new Express application.
const app = express();
// Initialize a new Express middleware to verify the webhook signature before
// processing the body.
// This will be called for each new incoming webhook.
app.use(bodyParser.json({
verify: function (req, res, buf) {
// print a message to notify when there is a new message
console.log("------------------- New message reveived -------------------")
// if the SECRET variable is defined, try to validate the webhook signature
if (secret) {
// retrieve the signature from the HTTP Headers
var signature = req.headers["x-mist-signature-v2"];
// calculate the expexted signature based on
// - the configured value of the SECRET variable
// - the Webhook body content
var digester = crypto.createHmac('sha256', secret)
.update(buf)
.digest('hex');
// if the received signature doesn't match the calculated one, send
// a HTTP401 response and throw an error to stop the processing
if (signature != digester) {
console.warn("Webhook signature doesn't match");
console.warn("Received signature: ${signature}");
console.warn("Calculated signature: ${digester}");
res.status(401).send();
throw new Error("Couldn't validate the request signature.");
}
// otherwise (the signature matches), continue the processing of the payload
else {
console.log("Webhook signature confirmed");
}
}
}
}));
// define a POST route for the webhool collector and define the webhook collector path to `/collector`
// this will be executed for each new webhook message received (if the signature matches)
app.post('/collector', express.json({ type: 'application/json' }), (request, response) => {
// when this point is reached, the signature is already validated
// print the JSON object
console.log("Webhook content: ")
console.log(request.body)
// send a HTTP200 response
response.status(200).send();
});
// start the Express App using the server_port variable defined above.
// the server will listen on this specific port
app.listen(server_port, () => {
console.log(`Server is running on port ${server_port}`);
});