AWS Signature V4 Express Middleware
raw JSON →aws4-express is an Express middleware library designed for validating AWS Signature Version 4 (SigV4) authenticated requests. It enables Express applications to act as SigV4-secured endpoints, mimicking AWS service behavior without requiring an actual AWS backend for authentication. The current stable version is 0.14.1, and the project demonstrates an active release cadence, frequently updating to support newer Node.js versions (currently >=20) and incorporating security enhancements. Its primary function is to abstract the complexities of SigV4 verification, providing an `awsVerify` middleware that integrates with Express's request lifecycle, notably requiring careful handling of the raw request body for accurate signature calculation. It is actively maintained with regular updates and security audits.
Common errors
error Error: SignatureDoesNotMatch ↓
secretKey callback is returning the correct secret for the accessKey. Ensure no middleware modifies the request body before awsVerify runs, and that rawBodyFromVerify is correctly used. Debug the client-side signing process to match server expectations. error TypeError: Cannot read properties of undefined (reading 'rawBody') ↓
express.json(), express.raw(), or express.urlencoded(), ensure you pass { verify: rawBodyFromVerify } to its configuration. For custom body parsing, ensure req.rawBody is manually populated with the exact raw request payload. error ERR_REQUIRE_ESM: require() of ES Module ... Not supported ↓
import syntax (import { awsVerify } from 'aws4-express';) and ensure your project is configured for ESM (e.g., "type": "module" in package.json). If strictly using CommonJS, ensure you are on v0.14.1 or later, which should have improved CJS compatibility due to the entrypoint fix. Warnings
breaking Support for Node.js versions below 20.x was officially dropped starting from `v0.13.0`. Users must ensure their environment runs Node.js 20 or higher to use recent versions of this package. ↓
gotcha AWS Signature V4 verification critically depends on the exact, raw request body. If using Express body parsers (like `express.json()`, `express.raw()`, or `express.urlencoded()`), you **must** attach the `rawBodyFromVerify` helper to the `verify` option to ensure `req.rawBody` is populated. Failure to do so will lead to `SignatureDoesNotMatch` errors. ↓
deprecated The library is currently in a "beta stage" (versions before 1.x.x). This means that minor version updates (e.g., 0.13.x to 0.14.x) may introduce breaking changes without a major version increment. Developers should carefully review the changelog for each update. ↓
gotcha Version `v0.14.1` fixed an issue where the `main` field in `package.json` was incorrect, potentially causing issues with CJS `require()` statements or incorrect module resolution in some bundlers. While not a direct breaking change, users on older `0.14.0` might have experienced import problems. ↓
breaking The initial `v0.4.0` release introduced breaking changes related to configuration parameters. As an alpha release, early users faced interface adjustments. ↓
Install
npm install aws4-express yarn add aws4-express pnpm add aws4-express Imports
- awsVerify wrong
const awsVerify = require('aws4-express').awsVerify;correctimport { awsVerify } from 'aws4-express'; - rawBodyFromVerify wrong
import { verify } from 'aws4-express';correctimport { rawBodyFromVerify } from 'aws4-express'; - rawBodyFromStream
import { rawBodyFromStream } from 'aws4-express';
Quickstart
import express from 'express';
import { awsVerify, rawBodyFromVerify } from 'aws4-express';
import aws4 from 'aws4';
import https from 'https';
const app = express();
// 1. Important: We need the raw body to check the signature!
// Must configure Express body parsers to provide rawBody.
app.use(express.json({ verify: rawBodyFromVerify }));
// 2. Add the AWS SigV4 security middleware
app.use(awsVerify({
secretKey: (message) => {
// 3. Implement your logic to find the secret for the incoming Access Key
// In a real application, this would involve a database lookup.
if (message.accessKey === 'MY_COOL_KEY') {
return 'MY_SUPER_SECRET';
}
return undefined; // Unknown key? Access denied!
}
}));
// 4. This route is protected by AWS SigV4 verification
app.get('/secret-club', (req, res) => {
res.send('Welcome to the VIP area! 🎉 If you see this, your signature was valid.');
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
console.log('--- Client Test ---');
// Example client-side usage with aws4 library
const opts = aws4.sign({
service: 'execute-api',
path: '/secret-club',
method: 'GET',
host: `localhost:${PORT}`,
headers: { 'Content-Type': 'application/json' }
}, {
accessKeyId: 'MY_COOL_KEY',
secretAccessKey: 'MY_SUPER_SECRET'
});
// Send the signed request
const clientReq = https.request(opts, res => {
console.log(`Client received status: ${res.statusCode}`);
res.pipe(process.stdout);
});
clientReq.on('error', (e) => console.error(`Client request error: ${e.message}`));
clientReq.end();
});