Modify http proxy request by adding auth token returned from another request
Asked Answered
H

1

6

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?

Hermelindahermeneutic answered 30/7, 2019 at 11:55 Comment(0)
C
6

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!

Concerned answered 31/12, 2019 at 4:9 Comment(2)
Forgot to post my solution, but I ended up doing the same, except that I call the proxy inside the middleware, so I only register that middleware, which I believe is better encapsulation.Hermelindahermeneutic
yeah i wish the onProxyReq function could accept an async function so that we could await a request before sending the proxy request, but this answer works well.Drunk

© 2022 - 2024 — McMap. All rights reserved.