Express HMAC Authentication Middleware

raw JSON →
9.0.0 verified Thu Apr 23 auth: no javascript

HMAC Auth Express provides middleware for Express applications to implement HMAC (Hash-based Message Authentication Code) authentication. It is currently at version 9.0.0 and demonstrates an active development cadence with regular updates. Key differentiators include zero runtime dependencies (only Express as a peer dependency), timing-safe comparisons, 100% code coverage, support for all standard hash algorithms, and built-in replay attack prevention. The library also features flexible secret management, allowing for static secrets or dynamic resolution via an async function. It ships with full TypeScript type definitions, enhancing developer experience and ensuring type safety in modern JavaScript projects.

error TypeError: 'secret' must be a string or a function.
cause The first parameter passed to the `HMAC` middleware factory is not a string (for a static secret) or a function (for a dynamic secret).
fix
Provide a string literal for your secret (e.g., HMAC('your-secret')) or a function that returns the secret (e.g., HMAC((req) => process.env.HMAC_SECRET_KEY)).
error Error: Invalid request, invalid timestamp.
cause The timestamp provided in the HMAC header (e.g., `Authorization: HMAC 12345:signature`) is either not a valid UNIX timestamp or falls outside the `maxInterval` / `minInterval` configured for replay attack prevention.
fix
Ensure the client-generated timestamp is a valid UNIX epoch timestamp (milliseconds) and that it is within the acceptable time window configured in the HMAC options (maxInterval, minInterval). Adjust client's system clock or server's options if time skew is the issue.
error Error: Invalid request, invalid signature.
cause The calculated HMAC signature on the server-side, based on the request content and secret, does not match the signature provided in the `Authorization` header by the client.
fix
Verify that the client is generating the HMAC signature correctly, using the same secret, algorithm, and canonicalization rules (e.g., body parsing, array ordering) as the server. Common causes include mismatched secrets, incorrect body serialization, or differences in the algorithm option.
breaking The `order` function, used internally for HMAC calculation, was fixed to correctly order array values. This change could lead to non-deterministic ordering if previous versions were used with arrays in a way that produced inconsistent HMACs. Consumers upgrading should re-verify HMAC generation if arrays are part of the signed payload.
fix Review how HMAC signatures are generated on the client-side, especially if request bodies or query parameters contain arrays. Ensure consistent array serialization/ordering between client and server for HMAC generation.
gotcha When authenticating routes that process request bodies (e.g., POST, PUT), the `hmac-auth-express` middleware MUST be registered *after* any body parsing middleware like `express.json()`. If `express.json()` is placed after `HMAC`, the middleware will not have access to the parsed `req.body`, leading to incorrect HMAC validation.
fix Ensure `app.use(express.json());` (or similar body parsers) is declared before `app.use(HMAC(...));` in your Express application setup.
gotcha The HMAC header (default `Authorization`) must be structured specifically as `Identifier Timestamp:Signature`. For example, `Authorization: HMAC 1573504737300:76251c63...`. Missing the identifier (default `HMAC`), incorrect timestamp format, or malformed signature will result in authentication failure.
fix Verify client-side HMAC header construction matches the expected format outlined in the documentation, including the identifier, UNIX timestamp, and the calculated hash signature separated by a colon.
gotcha Error handling for authentication failures can be done by checking `instanceof AuthError` or by inspecting the error code `error.code === 'ERR_HMAC_AUTH_INVALID'`. Failing to implement a specific error handler for these errors will result in Express's default error handling, which might not provide user-friendly responses.
fix Implement custom error handling middleware in Express to catch `AuthError` instances or errors with the code `ERR_HMAC_AUTH_INVALID` and return appropriate HTTP status codes (e.g., 401 Unauthorized) and messages.
npm install hmac-auth-express
yarn add hmac-auth-express
pnpm add hmac-auth-express

This quickstart demonstrates basic HMAC middleware registration, proper ordering with `express.json()`, and a custom error handler for authentication failures.

import express from 'express';
import { HMAC } from 'hmac-auth-express';

const app = express();
const port = process.env.PORT ?? 3000;

// IMPORTANT: express.json() MUST be registered BEFORE HMAC middleware
// if your routes process request bodies.
app.use(express.json());

// Basic middleware registration with a static secret
app.use('/api/v1', HMAC('my-super-secret-key'));

// Example route for a GET request
app.get('/api/v1/hello', (req, res) => {
  res.send('Hello, HMAC authenticated world!');
});

// Example route for a POST request that requires body parsing
app.post('/api/v1/data', (req, res) => {
  console.log('Received data:', req.body);
  res.json({ message: 'Data received and authenticated.', data: req.body });
});

// Error handling middleware for HMAC specific errors
app.use((error, req, res, next) => {
  if (error && error.code === 'ERR_HMAC_AUTH_INVALID') {
    return res.status(401).json({
      error: 'Authentication Failed',
      message: error.message
    });
  }
  next(error); // Pass other errors to the next handler
});

app.listen(port, () => {
  console.log(`Server listening at http://localhost:${port}`);
});