Express Middleware
Add automatic PEAC receipt issuance to your Express.js application. Every HTTP response gets a cryptographically signed PEAC-Receipt header with zero per-route boilerplate.
Drop peacMiddleware() into your Express app and every outgoing response automatically carries a verifiable receipt. No per-route code required.
Install
pnpm add @peac/protocol @peac/middleware-express
Basic setup
import express from 'express';
import { peacMiddleware } from '@peac/middleware-express';
const app = express();
app.use(
peacMiddleware({
privateKey: process.env.PEAC_PRIVATE_KEY,
kid: 'peac-2026-02',
issuer: 'https://api.example.com',
})
);
app.get('/api/data', (req, res) => {
res.json({ message: 'This response has a PEAC receipt' });
});
app.listen(3000);
Every response now includes a signed receipt:
HTTP/1.1 200 OK
Content-Type: application/json
PEAC-Receipt: eyJhbGciOiJFZERTQSIsInR5cCI6...
Configuration
Required options
| Option | Type | Description |
|---|---|---|
privateKey | string | Ed25519 private key (base64url or hex encoded) |
kid | string | Key ID -- must match the kid in your published JWKS |
issuer | string | Your service URL (becomes the iss claim) |
Optional options
| Option | Type | Default | Description |
|---|---|---|---|
audience | string | -- | Default audience for all receipts |
attestationType | string | 'interaction' | Default attestation type |
includeRequestHash | boolean | false | Hash the request body into the receipt payload |
skipPaths | string[] | [] | Paths to skip (e.g., ['/health', '/metrics']) |
onError | (err: Error) => void | log and continue | Custom error handler |
Route-specific configuration
Override the global middleware options on individual routes by applying peacMiddleware() directly:
app.post(
'/api/payment',
peacMiddleware({
privateKey: process.env.PEAC_PRIVATE_KEY,
kid: 'peac-2026-02',
issuer: 'https://api.example.com',
attestationType: 'payment',
}),
paymentHandler
);
Route-level middleware overrides the global instance for that route only. All other routes continue using the global configuration.
With payment evidence
Attach payment evidence from a rail adapter to enrich the receipt with commerce data:
import { fromStripePaymentIntent } from '@peac/rails-stripe';
app.post('/api/checkout', async (req, res) => {
const paymentIntent = await stripe.paymentIntents.create({ ... });
const evidence = fromStripePaymentIntent(paymentIntent);
// Attach evidence to the response for the middleware
res.locals.peacEvidence = evidence;
res.json({ success: true });
});
The middleware detects res.locals.peacEvidence and folds it into the signed receipt automatically.
Framework-agnostic core
The @peac/middleware-core package provides the framework-agnostic middleware logic. Use it to build middleware for Fastify, Koa, Hono, or any other Node.js framework.
import { createMiddlewareCore } from '@peac/middleware-core';
const core = createMiddlewareCore({
privateKey: process.env.PEAC_PRIVATE_KEY,
kid: 'peac-2026-02',
issuer: 'https://api.example.com',
});
// Use core.issueForRequest(request) in your framework adapter