node.jsproxyrequestauth-tokenhttp-proxy-middleware

Modify http proxy request by adding auth token returned from another request


I'm using the http-proxy-middleware (https://github.com/chimurai/http-proxy-middleware#http-proxy-events) to implement a simple proxy (call it my-proxy/) to another REST API (call it /rest-api) that requires the user to pass an auth token in the HTTP header auth-token. The token can be fetched from an endpoint POST /rest-api/auth with the credentials in the body.

I want my proxy to take incoming requests and check if auth-token is set in the the request header, and if not perform a POST /rest-api/auth to retrieve the token and set auth-token in the header before passing the request to rest-api/.

In the proxy config I specify

onProxyReq: function (proxyReq, req, res) {
        if (!req.header("auth-token")) {
            const authRequest = request({
                    url: 'rest-api/auth',
                    method: 'POST',
                    json: {"username": "user", "password": "pass"}
                },
                function (error, resp, body) {
                    proxyReq.setHeader("auth-token", body.token)
                }
            );
        }
    }

I can see the body.token return the right token. However the setHeader call fails with Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client.

I think this means the request I modify has already been sent to rest-api/ before waiting for the callback, but I don't know how this is best solved in my scenario.

Any help?


Solution

  • I met this same issue today. I workaround this by using a separate middleware (before http proxy).

    pseudo code

    // fix token stuff here in a separate middleware
    app.use('/api', async (req, res, next) => {
    
        if (!req.session.token) {
           const resToken = await axios.post(token_url, data, options)
           req.session.token = resToken.data
        }
        next()
    }
    
    // proxy middleware options
    const proxyOptions = {
      target: config.gateway.url, // target host
      changeOrigin: true,
      pathRewrite: function(path, req) {
        return path.replace('/api', '')
      },
      onProxyReq: function onProxyReq(proxyReq, req, res) {
        // add custom header to request
        let token = req.session.token
        if (token) {
          proxyReq.setHeader('Authorization', `bearer ${token.access_token}`)
        }
      },
      logLevel: 'debug',
    }
    
    app.use(proxy('/api', proxyOptions))
    

    Hope this helps!