{"id":16901,"library":"simple-hmac-auth-express","title":"Simple HMAC Authentication Express Middleware","description":"This package, `simple-hmac-auth-express`, provides an Express middleware designed for implementing HMAC-based authentication in API endpoints. It acts as a wrapper around the `simple-hmac-auth` core library, integrating its authentication logic seamlessly into the Express request-response cycle. The current stable version is v1.3.0, released in August 2022. Releases appear to be event-driven, primarily driven by updates to its core dependency or maintenance tasks. A key differentiator is its ability to handle request body parsing internally, which is crucial for HMAC signature verification that often requires access to the raw request body before other middleware might consume it. It requires `secretForKey` (a function returning a Promise for the secret) and `onRejected` handlers for failed authentication.","status":"active","version":"1.3.0","language":"javascript","source_language":"en","source_url":"https://github.com/jessety/simple-hmac-auth-express","tags":["javascript","typescript"],"install":[{"cmd":"npm install simple-hmac-auth-express","lang":"bash","label":"npm"},{"cmd":"yarn add simple-hmac-auth-express","lang":"bash","label":"yarn"},{"cmd":"pnpm add simple-hmac-auth-express","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Provides the core HMAC authentication logic and protocol specification.","package":"simple-hmac-auth","optional":false},{"reason":"Runtime peer dependency as this is an Express middleware.","package":"express","optional":false}],"imports":[{"note":"The package exports the middleware factory function as its default export. For TypeScript projects, this is the preferred ESM import.","wrong":"import { auth } from 'simple-hmac-auth-express';","symbol":"auth","correct":"import auth from 'simple-hmac-auth-express';"},{"note":"CommonJS `require` syntax for Node.js environments. The exported value is a function that, when called with options, returns the Express middleware.","symbol":"auth","correct":"const auth = require('simple-hmac-auth-express');"},{"note":"Imports the TypeScript type definition for the middleware's configuration options.","symbol":"HmacAuthMiddlewareOptions","correct":"import type { HmacAuthMiddlewareOptions } from 'simple-hmac-auth-express';"}],"quickstart":{"code":"import express from 'express';\nimport auth from 'simple-hmac-auth-express';\n\nconst app = express();\n\napp.use(auth({\n  // Required: Return a promise that resolves with the secret for the specified API key.\n  // This function is async since v1.3.0 and core library v4.0.0.\n  secretForKey: async (apiKey) => {\n    // In a real application, you would fetch the secret from a database or secure store\n    // based on the provided apiKey. For example purposes, we return a hardcoded secret.\n    if (apiKey === 'MY_API_KEY') {\n      return process.env.HMAC_SECRET_KEY ?? 'my-super-secret-key';\n    }\n    return null; // API key not found\n  },\n\n  // Required: Handle requests that have failed authentication.\n  onRejected: (error, request, response, next) => {\n    console.error(`Authentication failed for \"${request.apiKey}\": ${error.message} on ${request.method} ${request.url}`);\n    response.status(401).json({\n      error: {\n        message: error.message || 'Authentication Failed'\n      }\n    });\n  },\n  \n  // Optional: Handle requests that have passed authentication.\n  onAccepted: (request, response) => {\n    console.log(`\"${request.apiKey}\" authenticated request to ${request.method} ${request.url}`);\n  },\n\n  // Optional: Body-parser options. The middleware parses the body itself for signature verification.\n  // It should be placed before other body parsing middleware.\n  body: {\n    json: { strict: false, limit: '1mb' },\n    urlencoded: { extended: true, limit: '5mb' },\n    text: { type: 'application/octet-stream' }\n  }\n}));\n\napp.get('/protected', (req, res) => {\n  res.send(`Hello, authenticated user with API Key: ${req.apiKey}!`);\n});\n\napp.post('/protected-data', (req, res) => {\n  // Access parsed body if configured in 'body' options\n  res.json({ message: 'Data received and authenticated!', data: req.body });\n});\n\nconst PORT = process.env.PORT || 3000;\napp.listen(PORT, () => {\n  console.log(`Server running on port ${PORT}`);\n  console.log('Use MY_API_KEY and hmac signature for /protected and /protected-data');\n});","lang":"typescript","description":"This quickstart demonstrates how to set up `simple-hmac-auth-express` middleware in an Express application. It shows the basic configuration with `secretForKey` and `onRejected` functions, including optional body parsing settings. It provides an example of a protected route and how to access authenticated requests."},"warnings":[{"fix":"Update your `secretForKey` implementation to be an `async` function that directly `return`s the secret (or `null`/`undefined`) or a Promise that resolves with it, rather than using a callback. Example: `secretForKey: async (apiKey) => { /* ... */ return 'SECRET'; }`","message":"The `secretForKey` callback signature changed from a Node.js-style `(apiKey, callback)` to an `async (apiKey)` function that returns a Promise. Direct callback usage will no longer work and must be migrated to a Promise-returning asynchronous function.","severity":"breaking","affected_versions":">=1.3.0"},{"fix":"Review the changelog for `simple-hmac-auth` v4.0.0 for any specific breaking changes that might impact your HMAC signature generation or verification logic. Adjust client-side or server-side implementations as necessary.","message":"Version 1.3.0 of `simple-hmac-auth-express` bumps its core dependency `simple-hmac-auth` to v4.0.0. Any breaking changes introduced in `simple-hmac-auth` v4.0.0 will implicitly affect users of `simple-hmac-auth-express` v1.3.0 and later. Developers should consult the `simple-hmac-auth` changelog for further details.","severity":"breaking","affected_versions":">=1.3.0"},{"fix":"Ensure `simple-hmac-auth-express` middleware is placed *before* any other body parsing middleware in your Express application chain. If you need custom body parsing, configure it via the `body` option within the `simple-hmac-auth-express` middleware configuration.","message":"This middleware includes its own body parsing capabilities. If you use other body parsing middleware (like `express.json()` or `body-parser`) before `simple-hmac-auth-express`, the request body may already be consumed, leading to signature verification failures as the raw body required for HMAC calculation will be unavailable.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Always ensure your `onRejected` function sends a response (e.g., `res.status(401).json(...)`) or passes an error to the next middleware (`next(error)`) to properly terminate or handle the request. Do not leave the response open.","message":"The `onRejected` handler is crucial for responding to unauthenticated requests. If it does not explicitly terminate the request-response cycle (e.g., by sending a response or calling `next(error)` for an error handler), the request may hang or proceed unexpectedly, potentially causing 'Can't set headers after they are sent' errors.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Refactor `secretForKey` to be an `async` function that returns the secret directly or a `Promise.resolve(secret)`. Example: `secretForKey: async (apiKey) => { /* ... */ return 'mysecret'; }`.","cause":"The `secretForKey` function was implemented using a Node.js-style callback instead of returning a Promise, which is required since v1.3.0.","error":"TypeError: secretForKey must be a function that returns a promise"},{"fix":"Verify that your `onRejected` function explicitly sends a response (e.g., `response.status(401).json(...)`) or calls `next(error)` to propagate the error. Also, check for other middleware inadvertently sending responses.","cause":"The `onRejected` handler or another middleware tried to send a response or modify headers after `simple-hmac-auth-express` (or another middleware) had already finalized the response. This often happens if `onRejected` doesn't explicitly send a response or call `next(error)`.","error":"Error: Can't set headers after they are sent to the client."},{"fix":"Double-check the `secretForKey` implementation to ensure it returns the correct secret. Verify that client and server are hashing the *exact* same request components (method, path, headers, raw body). Ensure consistent body parsing, especially if the `body` option is used. Check for significant time differences between client and server.","cause":"This typically indicates that the HMAC signature calculated by the client does not match the one calculated by the server. Common causes include: incorrect `secretForKey` implementation, differences in how the request body is parsed/hashed, incorrect headers included in the signature, or clock skew between client and server.","error":"Signature mismatch error / 401 Unauthorized for valid requests"}],"ecosystem":"npm","meta_description":null}