author: Krasimir Tsonev

Hi there, I'm . Senior front-end engineer with over 13 years of experience. I write, speak and occasionally code stuff.

The simplest HTTP proxy with custom headers

The simplest HTTP proxy with custom headers Photo by Scott Webb

These days I had an interesting problem to solve. At work, on our staging environment, we have basic authorization. It works really well but for some older versions of Chrome we experienced a weird issue. The browser did not pass the authorization header. The app runs fine but as soon as it does a fetch request to a local endpoint the request fails with 401 not-authorized error. In the modern browsers that's not happening because the browser kinda knows that we came here with basic auth and automatically includes authorization: basic ... header.

So, our solution was to get the value of that header on the node backend, pass it down to the client and make sure that every fetch request have it in place. The task itself is not that difficult but what took me half a day is the simulation locally. I needed a request to my local server that contains a custom header. In my case this was authorization header. On staging we have a Kong gateway that provides the basic auth. The request first hits that gateway and if the credentials are correct it allows the request to our kubernetes pod with our node server inside. And there is an authorization header attached. Apparently, replicating this type of request locally is difficult.

The idea is to have a small proxy server running in parallel with my dev server. The proxy gets whatever comes in and attaches headers to it. In node is pretty trivial to pass custom headers as response to a request but not so trivial to do it when proxying. Here's the code that does the job for me:

const http = require('http');

function onRequest(req, res) {
  console.log('serve: ' + req.url);

  const options = {
    hostname: 'localhost',
    port: 9001,
    path: req.url,
    method: req.method,
    headers: {
      ...req.headers,
      'authorization': 'Basic foobar'
    }
  };

  const proxy = http.request(options, function (r) {
    res.writeHead(r.statusCode, r.headers);
    r.pipe(res, {
      end: true
    });
  });

  req.pipe(proxy, {
    end: true
  });
}

http.createServer(onRequest).listen(3000);
console.log('Listening on port 3000')

It's vanilla JavaScript/node. No express or anything. Just the native http module. Notice the options constant. My development server is running at the same time on localhost:9001 and this is the place where I want the requests to land. res.writeHead(r.statusCode, r.headers) is also quite important so we pass the original server response status and headers back.

That small proxy server is useful when you want to simulate the existence of headers but also when you want to overwrite or change them. Hope it safes you some time.