Express X-Hub Signature Middleware

raw JSON →
1.0.4 verified Thu Apr 23 auth: no javascript abandoned

The `express-x-hub` package provides an Express.js middleware for validating X-Hub-Signature requests. It was designed to ensure the integrity of incoming webhooks, particularly useful for platforms like Facebook real-time updates and GitHub webhooks, by verifying the request body against a secret using the `X-Hub-Signature` header. The current and only stable version is 1.0.4, last published in October 2015. This package is no longer actively maintained or updated, making it effectively abandoned. Its primary differentiation was its specific focus on adding validation methods directly to the `req` object (`req.isXHub`, `req.isXHubValid()`) within the Express middleware flow, requiring placement *before* any body parsing middleware. It does not provide official TypeScript types.

error Property 'isXHubValid' does not exist on type 'Request<{}, any, any, ParsedQs, Record<string, any>>'.
cause Missing TypeScript type declarations for the custom properties `express-x-hub` adds to the Express `Request` object.
fix
Add a TypeScript declaration file (e.g., src/types/express-x-hub.d.ts) to your project to augment the express.Request interface. Example content: declare namespace Express { interface Request { isXHub?: boolean; isXHubValid(): boolean; } }. Ensure this file is included in your tsconfig.json.
error Error: Invalid X-Hub Signature
cause The X-Hub signature in the request header does not match the signature calculated from the request body using the provided secret, or the X-Hub-Signature header is entirely missing (if `strict` option is `true`). This can also happen if the `express-x-hub` middleware is placed *after* a `body-parser` middleware, corrupting the raw body.
fix
1. Verify the secret configured in the middleware matches the secret used by the webhook sender. 2. Ensure the X-Hub-Signature header is present and correctly formatted in the incoming request. 3. Crucially, confirm that express-x-hub is mounted *before* any body-parser or other middleware that consumes the raw request body.
gotcha The `express-x-hub` middleware *must* be mounted before any `body-parser` middleware. X-Hub signatures are calculated over the raw request body. If `body-parser` processes the request first, the raw body will be consumed and unavailable for `express-x-hub`, leading to validation failures.
fix Ensure `app.use(xhub(...))` is called *before* `app.use(bodyParser.json())` or `app.use(bodyParser.urlencoded())`.
deprecated The `express-x-hub` package (v1.0.4) was last published in October 2015 and appears to be unmaintained and effectively abandoned. While it still functions, consider migrating to a more actively maintained X-Hub-Signature validation library, such as `x-hub-signature` (which offers a separate middleware package `x-hub-signature-middleware` for Express) for better security and ongoing support.
fix Evaluate newer, actively maintained alternatives like `x-hub-signature` and its dedicated Express middleware. Be aware of potential API differences when migrating.
gotcha This package does not ship with official TypeScript declaration files. When used in a TypeScript project, the `req.isXHub` and `req.isXHubValid()` properties will not be recognized by the compiler, leading to type errors unless custom declaration merging is used.
fix Manually extend the `express.Request` interface in your project to include `isXHub: boolean` and `isXHubValid: () => boolean`. Create a declaration file (e.g., `src/types/express-x-hub.d.ts`) with content like: `declare namespace Express { interface Request { isXHub?: boolean; isXHubValid(): boolean; } }`.
npm install express-x-hub
yarn add express-x-hub
pnpm add express-x-hub

This quickstart sets up a basic Express server with the `express-x-hub` middleware to validate incoming webhooks. It demonstrates the critical middleware order (before `body-parser`) and how to use `req.isXHub` and `req.isXHubValid()` to handle and verify signed requests.

import express from 'express';
import bodyParser from 'body-parser';
const xhub = require('express-x-hub');

const app = express();
const PORT = process.env.PORT || 3000;
const XHUB_SECRET = process.env.XHUB_SECRET || 'your-super-secret-key';

if (!XHUB_SECRET || XHUB_SECRET === 'your-super-secret-key') {
  console.warn('WARNING: XHUB_SECRET is not set or using default. Please set `process.env.XHUB_SECRET` for production.');
}

// IMPORTANT: express-x-hub middleware MUST be placed before body-parser
app.use(xhub({ algorithm: 'sha1', secret: XHUB_SECRET }));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.post('/webhook', (req, res) => {
  console.log('Received webhook request.');

  // Check if it's an X-Hub request at all
  if (!req.isXHub) {
    console.log('Request is not X-Hub.');
    return res.status(400).send('No X-Hub Signature Found');
  }

  // Validate the X-Hub signature
  if (!req.isXHubValid()) {
    console.warn('Invalid X-Hub Signature!');
    return res.status(401).send('Invalid X-Hub Signature');
  }

  // If valid, process the request
  console.log('X-Hub Signature is valid. Processing request body:', req.body);
  res.status(200).json({ status: 'X-Hub Is Valid', data: req.body });
});

app.get('/', (req, res) => {
  res.send('X-Hub test server running. Send POST requests to /webhook');
});

app.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`);
  console.log(`Test with: curl -X POST -H "X-Hub-Signature: sha1=your_test_signature" -H "Content-Type: application/json" -d '{"key":"value"}' http://localhost:${PORT}/webhook`);
});