chimurai / http-proxy-middleware

:zap: The one-liner node.js http-proxy middleware for connect, express, next.js and more
MIT License
10.72k stars 834 forks source link

Api behind Basic authentication and NTLM authentication #39

Open zychj1 opened 8 years ago

zychj1 commented 8 years ago

Hi, I have api on iis server behind basic windows authentication and i cannot use cors. So I tried to use this module but however I configure it I cannot log into api and I get 401 every time

I tried

    server.middleware = proxyMiddleware(
        '/api',
        {
            target: 'API_HOST',
            logLevel: 'debug'
        }
    );
    server.middleware = proxyMiddleware(
        '/api',
        {
            target: 'API_HOST',
            logLevel: 'debug',
            auth: 'LOGIN:PASS'
        }
    );
    server.middleware = proxyMiddleware(
        '/api',
        {
            target: 'http://LOGIN:PASS@API_HOST',
            logLevel: 'debug'
        }
    );
jndietz commented 7 years ago

@imsontosh Here is a small project that utilizes express, webpack-dev-middleware, http-proxy-middleware

https://github.com/jndietz/csharp-windows-auth

Let me know if you are wanting to know something specific and I'll try to help out.

imsontosh commented 7 years ago

@jndietz Thanks for your effort. Working like charm. Cheers 👍

jalaz commented 7 years ago

@jndietz, thanks for creating the example.

I noticed an interesting behavior running it. When a request takes a long time to run - it forces a user to enter credentials every time it receives a subsequent request. I basically experience the same issue running angular-cli proxy which uses webpack with http-proxy-middleware.

It is easy to reproduce if you put Thread.Sleep(TimeSpan.FromSeconds(5)); in the controller action and try to trigger an API action several times.

Do you have any ideas why it could be happening and how could be resolved?

CC @chimurai @imsontosh

mikedevita commented 7 years ago

thank you everyone for chiming in on this, I realize this is a closed issue but this helped solve an auth/CORS issue I had when trying to hit a MVC .NET 4.6 WebApi app which uses "Windows Authenticaton" and I couldn't get it to work during development for two reasons (CORS and NTLM not working well with axios).

My code for the proxy middleware is this:

import proxyMiddleware from 'http-proxy-middleware'
import Agent from 'agentkeepalive'

const bundler = webpack(config)

let middleware = [
  proxyMiddleware('/api', {
    changeOrigin: true,
    target: 'http://codefest.example.gov/Team7',
    agent: new Agent({
      maxSockets: 100,
      keepAlive: true,
      maxFreeSockets: 10,
      keepAliveMsecs: 100000,
      timeout: 6000000,
      keepAliveTimeout: 90000 // free socket keepalive for 90 seconds
    }),
    onProxyRes: (proxyRes) => {
        var key = 'www-authenticate';
        proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
    }
  })
 // ... removed for brevity
];

// ... removed for brevity

browserSync({
  port: 3000,
  ui: {
    port: 3001
  },
  open: false,
  server: {
    baseDir: 'src',
    middleware
  }
});

The ending result was webpack/browserSync serving up my ReactJs UI at http://localhost:3000/ and during dev it would hit http://localhost:3000/api/values browserSync would intercept the /api/values and proxy it to the backend WebApi at http://codefest.example.gov/Team7/api/values. This works well, thanks again for all of your inputs.

xcjs commented 6 years ago

I just wanted to confirm that I'm still seeing an infinite series of pop-ups requesting authentication after trying various suggestions in this thread and ensuring that my dependencies include the fixes mentioned throughout.

I'm a little confused whether this issue is considered resolvable or not. As of now, has anyone successfully built a solution utilizing Webpack/http-proxy-middleware with NTLM authentication?

Usman-M commented 6 years ago

I still have this issue as well and have been monitoring to see if/when it gets resolved. IE11 seems to accept credentials from a single popup. No other browser does.

mike-schenk commented 6 years ago

@xcjs , The solution from @jndietz worked for me while all the other solutions attempting to use webpack-dev-server caused me to get never ending authentication prompts in both Chrome and Firefox.

The authentication prompt still appears sometimes; it seems to be while Chrome dev tools are open and I try a full refresh. But it works pretty well.

xcjs commented 6 years ago

@mike-schenk The solution from @jndietz unfortunately didn't have the same effect for me. I'm not expecting the prompt to never show, but I can't access the page due to the stream of authentication prompts.

jndietz commented 6 years ago

@jalaz @xcjs Hey guys -- sorry that wasn't working for you. I will need to dive a bit deeper into it and see what exactly is going on. Currently stuck working on setting up an angular 1 application to be built with webpack so I might be able to take a look at it soon.

jndietz commented 6 years ago

@jalaz @xcjs

I'm able to reproduce the issue in my project. I must not have seen that happen back when I made it.

With our Angular 1/Webpack config, we are going to be putting our UI code in with our web layer so we don't have any issues. If we weren't using Windows integrated authentication I don't suspect this would be as big of an issue. The alternative would be configuring the proxy as stated above, but then development activities would have to take place in Internet Explorer/Edge only and dealing with the username/password dialog from time to time.

The former was a better compromise for us. I still want to figure out a resolution for this :)

bkrrrr commented 6 years ago

same here. I switched back from gulp to grunt because of this. btw. (grunt-connect-proxy) is doing it correct.

bkrrrr commented 6 years ago

Update for BASIC authentication:

i figured out that it is necessary to forward explizit the authorization header. In case you want to enter the password over browser buildin popup: this should work.

proxy('/sap', {
        target: 'http://' + configBuild.sap.server + ':' + configBuild.sap.port,
        changeOrigin: true,
        onProxyRes: function (proxyRes, req, res) {
            if (proxyRes.headers['authorization']){
                proxyRes.headers['authorization'] = req.headers['authorization'];
            }
        }
}

But i'm still looking for a solution in CL(Karma) environment.

srkt commented 5 years ago

Thank you after few hours of hair pulling .. this link resolved my issue

ahrpee commented 5 years ago

Here is my working configuration with Vue-cli 3 / .NET WebAPI

Install package

npm install agentkeepalive --save

Update vue.config.js

const Agent = require('agentkeepalive');

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost',
        changeOrigin: true,
        agent: new Agent({
          maxSockets: 100,
          keepAlive: true,
          maxFreeSockets: 10,
          keepAliveMsecs: 1000,
          timeout: 60000,
          freeSocketTimeout: 30000
        }),
        onProxyRes: proxyRes => {
          var key = 'www-authenticate';
          proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
        }
      }
    }
  }
}
richardtallent commented 5 years ago

The above configuration (and some variations messing with the numbers) partially works for me. When I hit my home page, which makes 3 API calls, it usually works, but sometimes, I'll get another auth prompt for one of the API calls, but not the others. When I navigate to another route on the site, I get the never-ending prompts for the new route's API calls.

I'm using Chrome and Vue UI , and the proxy is connecting to IIS Express on Windows 7 using NTLM authentication. Going directly to the site on IIS Express always works fine, but that doesn't give me Vue hot-reload.

fredjeck commented 5 years ago

I have been using the above configuration as well and worked almost flawlessly (except sometimes a logging prompt which could be solved by restarting the dev server). Since I upgraded my project to the latest version of Angular and Angular CLI, the solution is not working anymore. A bug has been opened here but I think the issue lies int http-proxy-middleware. http-proxy-middleware@0.19.1 is not working with the above solution http-proxy-middleware@0.18.0 is working

Perogy commented 5 years ago

I have the exact same issue as @richardtallent, it works very intermittently, sometimes even perfectly for hours at a time and then will randomly start hitting me with multiple login pop-ups that don't seem to care whether I enter my credentials correctly or not.

Sometimes restarting my local web server fixes it, sometimes it doesn't. Rebuilding the project also sometimes fixes it.

I've played around with the agentkeepalive settings alot to no success (I have no idea what these settings actually do, and there's little explanation).

Will just have to go without hot reload for now

DustinDSchultz commented 5 years ago

@richardtallent, @Perogy, I'm having this issue too. I've been dealing with it for about 3 months and I've been trying to find a pattern to it and haven't been able to come up with anything tangible. I've tried everything recommended here and spent quite a few hours digging into the requests myself. I'm using it to proxy calls through my dev server to our backend API to bypass CORS in development since CORS isn't required by our prod configuration. For some reason the last few days have been pretty unbearable, probably because we recently moved our API to the cloud.

Aaron-Pool commented 5 years ago

Bump for the last four comments. I'm in the same boat. The suggestions here work sometimes, but sometimes the connection still putters out and starts throwing authentication prompts. I think it has something to do with keeping the authenticated TCP connection open. But my knowledge of server protocols is pretty limited.

sm-cdecker commented 5 years ago

I've had pretty good success with the agentkeepalive module, though for some reason it does NOT like signalr. If I try to route signalr calls through the proxy it just seems to break all the other calls and I wind up with the infinite login prompt. Maybe its an issue of websockets+ntlm?

mgoertz-dev commented 4 years ago

I have the same issue as @richardtallent and @Perogy. I am temporarily using the work around that restricts the maxSockets to 1, which seems to minimize the frequency of the issue but am wondering if there is any update on a resolution?

maa105 commented 4 years ago

I tried this instead of just fixing the www-authenticate header. it worked intermittently like once it work and 10 times it wont :(


proxy.on('proxyRes', function (proxyRes, req, res) {
  // var key = 'www-authenticate';
  // proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');

  var headersFirstKey = {};
  var headers = {};
  for(var i = 0; i < proxyRes.rawHeaders.length; i += 2) {
    var headerKey = proxyRes.rawHeaders[i];
    var headerValue = proxyRes.rawHeaders[i + 1];

    var headerKeyLower = headerKey.toLowerCase().trim();
    headerKey = headersFirstKey[headerKeyLower] || headerKey;
    headersFirstKey[headerKeyLower] = headerKey;
    headers[headerKey] = headers[headerKey] ? headers[headerKey] : [];
    headers[headerKey].push(headerValue)
  }
  for(var j in headers) {
    proxyRes.headers[j] = headers[j];
  }
});

also tried:


require('https').createServer({
  key: fs.readFileSync('key.key', 'utf8'),
  cert: fs.readFileSync('crt.crt', 'utf8'),
  passphrase: 'test',
  rejectUnauthorized: false,
  handshakeTimeout: 100000,
  insecureHTTPParser: true,  // maybe :|
  maxHeaderSize: 10000000
},
function (req, res) {
  proxy.web(req, res);
})
.on('secureConnection', (socket) => { // to keep connection open with client
  socket.setKeepAlive(true, 10000).setTimeout(60000);
})
.listen(443);
sam-michael commented 4 years ago

Do not use the simple agentkeepalive use instead agentkeepalive-ntlm

https://github.com/pappan123/agentkeepalive-ntlm

Here is a quick description explaining the issue:

The main motivation for this fork from agentkeepalive was to support user specific NTLM sessions. For NTLM to work, the TCP connection has to be authorized for a user. When we use the base 'agentkeepalive', sockets are authorized using a combination of the host + port. eg yahoo.com:443. However if multiple users are trying to access a NTLM enabled site, the socket connections were getting mixed up between users. Changed the implementation to include 'host+port+cookieName' while assigning sockets

If you use the code shown by mikedevita it must work.

babycasper123 commented 4 years ago

Here is my working configuration with Vue-cli 3 / .NET WebAPI

Install package

npm install agentkeepalive --save

Update vue.config.js

const Agent = require('agentkeepalive');

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost',
        changeOrigin: true,
        agent: new Agent({
          maxSockets: 100,
          keepAlive: true,
          maxFreeSockets: 10,
          keepAliveMsecs: 1000,
          timeout: 60000,
          freeSocketTimeout: 30000
        }),
        onProxyRes: proxyRes => {
          var key = 'www-authenticate';
          proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
        }
      }
    }
  }
}

This worked ! You are a gem :) <3 I was having CORS issues with .net core back end API where only windows auth could be enabled and no anonymous auth , this was causing preflight error. Your solution works perfectly with the proxy server.

alexmnv commented 3 years ago

Here is my working configuration with Vue-cli 3 / .NET WebAPI

Install package

npm install agentkeepalive --save

Update vue.config.js

const Agent = require('agentkeepalive');

module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost',
        changeOrigin: true,
        agent: new Agent({
          maxSockets: 100,
          keepAlive: true,
          maxFreeSockets: 10,
          keepAliveMsecs: 1000,
          timeout: 60000,
          freeSocketTimeout: 30000
        }),
        onProxyRes: proxyRes => {
          var key = 'www-authenticate';
          proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
        }
      }
    }
  }
}

I had an issue with NTLM authentication when subsequent auth requests failed (usually after reloading the page). The issue turned out to be that Agent performed NTLM auth requests with different connections from the pool.

Changing maxFreeSockets to 1 solved the issue.

mvpete commented 2 years ago

Hello -- I have information on what is causing this issue. My background isn't in the JavaScript/node world, meaning I don't have the relevant experience to go it alone. So if someone wants to chat about this issue. I'd love to tackle it together.

In short, there seems to be two issues. The first solved by

var key = 'www-authenticate';
          proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');

Is that the proxy was collapsing the www-authenticate headers into one line. Something like

WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM

into

WWW-Authenticate: Negotiate, NTLM

Seemingly, the browser will not begin the NTLM negotiation when it's collapsed. Even though, I think that's okay as per the standard. But the browser (I was using chrome) doesn't like it and won't reply to the challenge.

The problem with the infinite authentication dialogs comes from the real problem. Which is that NTLM negotiation requires a single TCP connection which is kept alive. The NTLM negotiation happens in 3 parts. The original request, the first challenge, and a second challenge. After the TCP socket is authenticated, as long as it stays alive each successive request will work without auth.

When we're proxying, there doesn't seem to be a connection between the incoming (from the browser), and the outgoing (to the IIS server). Why is this a problem? Because the 3 part handshake which happens in 3 separate requests through the proxy, can happen on 3 different outgoing sockets to the server. So the browser, and the server both get confused.

In order to mitigate this, I was able to set the outgoing agent configuration to use a single socket maxSockets : 1, and keep alive to true, with a long timeout keepAlive : true, timeout : 999999. This tells the http.Agent to keep the outgoing sockets alive, for a long time. The maxSockets, tells it to only use one outgoing connection. This works, for the most part. However, it's slow, and it's not quite right. Because if you look at an actual interaction between the browser and IIS server, it'll use the same socket for multiple requests. However, if you wireshark between the browser and the proxy, and the proxy and the server. You see multiple requests on several incoming sockets from the browser, and they all share the single outgoing socket (which is what makes this work) to the server.

Ideally, with NTLM the proxy should maintain the browser connection one-to-one, with the server.

Hopefully this makes sense. I empathize with everyone in this thread who's been having this issue.

NiceStepUp commented 2 years ago

We are not using http-proxy-middleware. However, maybe you can give me advice where I can ask question or maybe give me advice.

Description of what the bug is

We are developing at Windows 10. Our backend is ASP.NET Core 3.1 MVC

Windows Security dialog window pops up while I am developing an application through React. It is really annoying. We have to refresh page.

At first, this image is shown: enter image description here

Then the above dialog window is replaced by the following dialog window. It requires smart card credentials:

enter image description here

Settings of our application

package.json looks like this:

"devDependencies": {
    "@babel/cli": "7.14.3",
    "@babel/core": "7.14.3",
    "@babel/plugin-proposal-decorators": "7.14.2",
    "@babel/plugin-transform-runtime": "7.8.3",
    "@babel/preset-env": "7.14.4",
    "@babel/preset-react": "7.13.13",
    "@babel/preset-typescript": "7.13.0",
    "@testing-library/jest-dom": "^5.16.2",
    "@testing-library/react": "^11.2.7",
    "@types/jest": "^27.5.1",
    "@types/node": "14.17.1",
    "@types/react": "17.0.8",
    "@types/react-dom": "17.0.5",
    "@types/webpack": "5.28.0",
    "@typescript-eslint/eslint-plugin": "4.25.0",
    "@typescript-eslint/parser": "4.25.0",
    "agentkeepalive": "4.2.1",
    "axios-mock-adapter": "^1.21.1",
    "babel-loader": "8.2.2",
    "css-loader": "5.2.6",
    "eslint": "7.27.0",
    "eslint-config-prettier": "8.3.0",
    "eslint-plugin-prettier": "3.4.0",
    "eslint-plugin-react": "7.23.2",
    "express": "4.17.1",
    "file-loader": "6.2.0",
    "html-webpack-plugin": "5.3.1",
    "husky": "6.0.0",
    "image-webpack-loader": "7.0.1",
    "jest": "^27.5.1",
    "lint-staged": "11.0.0",
    "prettier": "2.3.0",
    "react-hot-loader": "4.13.0",
    "rimraf": "3.0.2",
    "style-loader": "2.0.0",
    "ts-jest": "^27.1.3",
    "typescript": "4.3.2",
    "webpack": "5.38.1",
    "webpack-cli": "4.7.0",
    "webpack-dev-server": "3.11.2",
    "webpack-merge": "5.7.3"
},
"dependencies": {
    "@hot-loader/react-dom": "17.0.1",
    "@svgr/cli": "6.2.1",
    "@types/lodash": "4.14.170",
    "antd": "4.16.2",
    "axios": "^0.27.2",
    "classnames": "^2.3.1",
    "dotenv": "^16.0.1",
    "lodash": "4.17.21",
    "mobx": "6.3.2",
    "mobx-react": "7.2.0",
    "moment": "2.29.1",
    "process": "0.11.10",
    "react": "17.0.2",
    "react-base-table": "1.12.0",
    "react-dnd": "14.0.2",
    "react-dnd-html5-backend": "14.0.0",
    "react-dom": "17.0.2",
    "react-router-dom": "6.2.1",
    "react-sortable-hoc": "2.0.0",
    "ts-loader": "9.2.3"
}

In addition, we are using proxy. The settings are applied from this official React docs.

Moreover, we are using agentkeepalive.

Config of proxy file looks like this:

// development config
require('dotenv').config()
const package = require('../../package.json')
const { merge } = require('webpack-merge')
const webpack = require('webpack')
const commonConfig = require('./common')
const agent = require('agentkeepalive')

module.exports = (webpackConfigEnv, argv) =>
    merge(commonConfig(argv), {
        mode: 'development',
        entry: [
            'react-hot-loader/patch', // activate HMR for React
            'webpack-dev-server/client?http://localhost:3030', 
            'webpack/hot/only-dev-server',
            './index.tsx', // the entry point of our app
        ],
        devServer: {
            port: 3030,
            hot: true, // enable HMR on the server
            historyApiFallback: true,
            proxy: {
                '/api/*': {
                    target: argv.env.mock ? '' : process.env.API_URL,
                    secure: false,
                    changeOrigin: true,
                    agent: new agent({
                        maxSockets: 100,
                        keepAlive: true,
                        maxFreeSockets: 10,
                        keepAliveMsecs: 100000,
                        timeout: 6000000,
                        freeSocketTimeout: 90000, // free socket keepalive for 90 seconds
                    }),
                    onProxyRes: (proxyRes) => {
                        var key = 'www-authenticate'
                        proxyRes.headers[key] =
                            proxyRes.headers[key] && proxyRes.headers[key].split(',')
                    },
                },
            },
        },
        devtool: 'cheap-module-source-map',
        plugins: [
            new webpack.HotModuleReplacementPlugin(), // enable HMR globally
            new webpack.DefinePlugin({
                'process.env.appVersion': JSON.stringify(package.version),
                'process.env.isMockMode': JSON.stringify(argv?.env?.mock),
                'process.env.isDevelopment': true,
            }),
        ],
    })

The current behavior

Windows Security dialog window sometimes pops up while I am developing an application through React. It is really annoying. We have to refresh page

The expected behavior

Windows Security dialog window sometimes DOES NOT POP UP while we are developing an application through React.

What we tried

We tried to set this option of axios, nevertheless the "Sign in" still pops up

axios.defaults.withCredentials = true;

UPDATE:

This is one of the URL that can return the 401 response with www-authenticate header-key:

 http://localhost:3030/api/notifications

Moreover, sometimes other methods can return 401 response. It is not always the same method return 401 response.

enter image description here

wolfie82 commented 1 year ago

I was having this problem of re-authentication, even after entering my credentials. It appeared stable at some points, and not at others. Anyways, I finally found a configuration for utilizing a proxy that is communicating with an API utilizing NTLM (that works for me). Since applying this, I have yet to have the constant re-auth issue. Just posting it here in the event it helps anyone else.

Note, this was for an Angular project, but I believe http-proxy-middleware is leveraged. Note, the onProxyReq can be removed. Also, I access the webserver @ https://localhost:4200, not https://127.0.0.1.

const { HttpsAgent } = require('agentkeepalive-ntlm');

const keepaliveAgentNTLM = new HttpsAgent({
  cookieName: 'localhost',
  maxSockets: 100,
  keepAlive: true,
  maxFreeSockets: 10,
  freeSocketTimeout: 30000,
  timeout: 60000,
  keepAliveMsecs: 300000,
});

const onProxyRes = (proxyRes, req, res) => {
  let key = 'www-authenticate';
  proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
};

const onProxyReq = (proxyReq, req, res) => {}

module.exports = {
  '/api/*': {
    host: '<HOST>',
    port: 443,
    path: '/api/*',
    target: "https://<HOST>",
    secure: false,
    logLevel: "debug",
    changeOrigin: true,
    agent: keepaliveAgentNTLM,
    onProxyRes,
  }
};
adolfox commented 1 year ago

I think I found a solution to the infinite popups, I simply changed the maxSockets to 1. Probably not the best solution but it seems to work.

My Agent is set up this way:

return new Agent({
    maxSockets: 1, 
    keepAlive: true,
    maxFreeSockets: 10,
    keepAliveMsecs:100000,
    timeout: 600000,
    keepAliveTimeout: 90000   
  });

Hope that helps!

This solved the authentication popup issue for me, along with @mvpete 's explanation. The insidious part of this issue for me was that at first the keepaliveagent settings suggested by @chimurai worked, but as I added more API calls to my app, the login/authentication popup started displaying intermittently. After a few refreshes, it would stop popping up. I now understand that per @mvpete explanation there was probably only two or three sockets being used and once the api calls that were causing the login pop got routed through the one socket that had done the NTLM authentication, then the login dialog would stop showing.

adolfox commented 1 year ago

I was having this problem of re-authentication, even after entering my credentials. It appeared stable at some points, and not at others. Anyways, I finally found a configuration for utilizing a proxy that is communicating with an API utilizing NTLM (that works for me). Since applying this, I have yet to have the constant re-auth issue. Just posting it here in the event it helps anyone else.

Note, this was for an Angular project, but I believe http-proxy-middleware is leveraged. Note, the onProxyReq can be removed. Also, I access the webserver @ https://localhost:4200, not https://127.0.0.1.

const { HttpsAgent } = require('agentkeepalive-ntlm');

const keepaliveAgentNTLM = new HttpsAgent({
  cookieName: 'localhost',
  maxSockets: 100,
  keepAlive: true,
  maxFreeSockets: 10,
  freeSocketTimeout: 30000,
  timeout: 60000,
  keepAliveMsecs: 300000,
});

const onProxyRes = (proxyRes, req, res) => {
  let key = 'www-authenticate';
  proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
};

const onProxyReq = (proxyReq, req, res) => {}

module.exports = {
  '/api/*': {
    host: '<HOST>',
    port: 443,
    path: '/api/*',
    target: "https://<HOST>",
    secure: false,
    logLevel: "debug",
    changeOrigin: true,
    agent: keepaliveAgentNTLM,
    onProxyRes,
  }
};

I went and read about agentkeepalive-ntlm and it says:

Since NTLM works on the principal of the same user connecting over a authorized socket, we should reuse the same socket per URL for a user.

So it's essentially doing the same thing as setting maxSockets: 1. In my case, I only need to use http-proxy-middleware when developing locally. My API runs in Visual Studio and my frontend in VS Code. For me, just the regular keepaliveagent worked by setting the maxSockets to 1. agentkeepalive-ntlm seems to be more if you need this in production and you need to support multiple concurrent users, e.g. cloud environment and such.

dsebata commented 6 months ago

Having followRedirects: true in the proxy config can also cause this error.

mvpete commented 6 months ago

I'm still open to work on this with someone, I can help with the protocol side.