Webhook Handshakes and Challenges

Webhooks enable interoperability between services and event-driven applications. To ensure secure and reliable communication, some services implement handshakes and challenges as part of their webhook URL registration process.

This guide will explain what webhook handshakes and challenges are, why they exist, and how to implement them.

Why Do Services Use Webhook Handshakes and Challenges?

Webhook handshakes and challenges are security mechanisms used to confirm that the URL you provided is valid and that a server is ready and willing to receive webhook events. This validation step can be important to ensure that URLs are not registered to servers maliciously in an attempt to create a denial of service attack.

What are Webhook Handshakes?

A webhook handshake is a verification process that occurs when you first register a webhook URL with a service. The service sends a verification request to your webhook URL, and your server must respond with a specific pre-defined token or code to confirm the handshake.

How Handshakes Work

  1. Registration: You register your webhook URL with the service.
  2. Verification Request: The service sends a verification request to your webhook URL.
  3. Response: Your server responds to the verification request with a specific response, usually a predefined token or a specific HTTP status code.
  4. Confirmation: If the response is correct, the service confirms the webhook URL and starts sending events to it.

Example: Implementing a Handshake

Here's an example of how to implement a webhook handshake in Node.js using Express:

const express = require('express');
const app = express();
const port = 3000;

// Middleware to parse JSON bodies
app.use(express.json());

// Endpoint to handle webhook handshake
app.post('/webhook', (req, res) => {
  const verificationToken = 'your-verification-token';
  
  // Check if the request contains the verification token
  if (req.body.token === verificationToken) {
    // Respond with the verification token to confirm the handshake
    res.status(200).send(verificationToken);
  } else {
    // Respond with a 400 status code if the token is invalid
    res.status(400).send('Invalid token');
  }
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

What are Webhook Challenges?

A webhook challenge is a security mechanism used to ensure that incoming webhook requests are legitimate and have not been tampered with. Challenges typically involve the service sending a unique token or challenge code with each webhook request, which your server must verify.

How Challenges Work

  1. Event Delivery: The service sends an event to your webhook URL, including a challenge token.
  2. Verification: Your server verifies the challenge token by creating a hash using the token with a shared secret to ensure the request is from a trusted source.
  3. Processing: If the token is valid, your server processes the event. If not, it rejects the request.

Example: Implementing a Challenge

const express = require('express');
const crypto = require('crypto');
const app = express();
const port = 3000;

// Middleware to parse JSON bodies
app.use(express.json());

// Secret key used to verify the challenge token
const secret = 'your-secret-key';

// Endpoint to handle incoming webhook events
app.post('/webhook', (req, res) => {
  const challengeToken = req.headers['x-challenge-token'];
  
  // Verify the challenge token
  const hash = crypto.createHmac('sha256', secret)
                     .update(challengeToken)
                     .digest('hex');
  
  if (hash === req.body.expectedHash) {
    // Process the event if the token is valid
    console.log('Event received:', req.body.event);
    res.status(200).send('Event processed');
  } else {
    // Respond with a 400 status code if the token is invalid
    res.status(400).send('Invalid challenge token');
  }
});

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

Conclusion

Webhook handshakes and challenges are mechanisms to verify the legitimacy of webhook registartions and protect your server from unwanted webhook callbacks from unexpected services. The examples provided in this guide demonstrate how to implement handshakes and challenges in Node.js using Express, but the concepts can be applied to other programming languages and frameworks as well.