Search code examples
expresssignature

How to sign JSON responses in Express


I'm developing an Express.js server; since it manages sensible data, I'd like to add a cryptographic signature to every response, using a private key. The signature part is already OK, the problem is catching the JSON string just before is sent to the client to sign it.

Ideally I'd like to add a custom response header, e.g. X-signature, so clients could verify the received payload against the public key exposed by the service.

In Express, how can I intercept the response body after the JSON.stringify() call but before the headers are sent?


Solution

  • I've copied what is done in the compression() middleware, replacing the send() method of Response with my own and calling the original one after I calculate the signature. Here's a simplified solution just to show the concept, in the real word I've taken care of body's possible types. The fact that calculateSignature() is an async function is a little troublesome, but everything seems to work well now.

    Any comment is appreciated!

    import express, { RequestHandler } from 'express';
    
    declare const calculateSignature = (payload: string) => Promise<string>;
    
    const responseSignature = (): RequestHandler => (_, res, next) => {
        const _send = res.send;
        res.send = (body) => {
            if (isPlaintextType(body)) {
                calculateSignature(body)
                    .then((signature) => res.setHeader('X-Signature', signature))
                    .catch((e) => console.error(e))
                    .finally(() => _send.call(res, body));
                return res;
            } else {
                return _send.call(res, body);
            }
        };
        next();
    };
    
    
    const app = express();
    app.use(responseSignature());
    app.listen(3000);