Node.js NTLM Client (Legacy)

raw JSON →
0.1.2 verified Thu Apr 23 auth: no javascript abandoned

This package, `node-ntlm-client` at version 0.1.2, provides a client-side implementation for NTLM and NTLMv2 authentication in Node.js environments. It exposes functions for generating NTLM Type 1 and Type 3 messages, and decoding Type 2 messages, enabling developers to implement the NTLM handshake manually. It also includes a `request` convenience function that relies on the now-deprecated `request` HTTP client library. This package has seen no updates in approximately ten years and is considered abandoned, making it unsuitable for new projects. Modern alternatives typically use native Node.js `http`/`https` modules or other maintained HTTP clients, often with fewer external dependencies and better support for contemporary Node.js versions and language features like ESM.

error Cannot find module 'request'
cause The package's `request` convenience function depends on the `request` npm module, which must be installed separately, or was not resolved correctly by the package manager.
fix
Install the request dependency explicitly: npm install request. However, it is highly recommended to avoid the deprecated request function and instead use the core NTLM message functions with a modern HTTP client.
error TypeError: createType1Message is not a function
cause This error typically occurs when attempting to use ES Module `import` syntax with a CommonJS-only package, or when trying to destructure a module that exports functions directly rather than as named exports from a default object.
fix
Ensure you are using CommonJS require syntax: const { createType1Message } = require('ntlm-client');.
breaking The package includes a convenience `request` function that internally uses the `request` npm package, which has been deprecated since 2019 and is no longer maintained. Using this function may lead to security vulnerabilities or compatibility issues with newer Node.js versions.
fix Avoid using the `request(options)` convenience function. Instead, manually implement the NTLM handshake using `createType1Message`, `decodeType2Message`, and `createType3Message` with a modern HTTP client like `axios`, `node-fetch`, or Node.js's native `http`/`https` module.
deprecated The `node-ntlm-client` package appears to be abandoned, with no updates in approximately a decade. This means it likely lacks support for newer Node.js features, security patches, or bug fixes, making it a poor choice for ongoing development.
fix Consider migrating to actively maintained NTLM client libraries for Node.js, such as `node-client-ntlm` or `node-http-ntlm`, which offer better compatibility and security.
gotcha NTLM authentication itself is considered less secure than Kerberos and is being phased out by Microsoft. Relying on NTLM may introduce security risks and compatibility challenges with modern enterprise environments.
fix Prioritize authentication methods like Kerberos or OAuth when interacting with Windows-based services. If NTLM is unavoidable, ensure all network communication is secured with HTTPS.
npm install node-ntlm-client
yarn add node-ntlm-client
pnpm add node-ntlm-client

This example demonstrates a conceptual NTLM Type 1, Type 2, and Type 3 message exchange using the core functions, simulating interaction with an NTLM-protected server using native Node.js `http` module. Set NTLM_SERVER_URL, NTLM_USERNAME, NTLM_PASSWORD environment variables for a real NTLM server.

const { createType1Message, decodeType2Message, createType3Message } = require('ntlm-client');
const http = require('http'); // Using native http for demonstration

const NTLM_SERVER_URL = process.env.NTLM_SERVER_URL ?? 'http://localhost:8080/protected';
const USERNAME = process.env.NTLM_USERNAME ?? 'user';
const PASSWORD = process.env.NTLM_PASSWORD ?? 'pass';
const WORKSTATION = process.env.NTLM_WORKSTATION ?? require('os').hostname();
const DOMAIN = process.env.NTLM_DOMAIN ?? '';

async function performNtlmHandshake() {
  let type1Msg = createType1Message(WORKSTATION, DOMAIN);
  console.log('Sending Type 1 message...');

  // Step 1: Send Type 1 message
  let response1 = await sendHttpRequest(NTLM_SERVER_URL, 'GET', { 'Authorization': `NTLM ${type1Msg}` });

  if (response1.statusCode === 401 && response1.headers['www-authenticate']) {
    const wwwAuthenticateHeader = response1.headers['www-authenticate'];
    const type2Match = wwwAuthenticateHeader.match(/NTLM (.*)$/);

    if (type2Match && type2Match[1]) {
      console.log('Received Type 2 message. Decoding...');
      let type2Msg = decodeType2Message(type2Match[1]);
      let type3Msg = createType3Message(type2Msg, USERNAME, PASSWORD, WORKSTATION, DOMAIN);
      console.log('Sending Type 3 message...');

      // Step 2: Send Type 3 message
      let response2 = await sendHttpRequest(NTLM_SERVER_URL, 'GET', { 'Authorization': `NTLM ${type3Msg}` });

      if (response2.statusCode === 200) {
        console.log('NTLM authentication successful!');
        console.log('Response body:', response2.body.toString().substring(0, 100) + '...');
      } else {
        console.error('NTLM authentication failed at Type 3 stage. Status:', response2.statusCode);
      }
    } else {
      console.error('No NTLM Type 2 message found in WWW-Authenticate header.');
    }
  } else if (response1.statusCode === 200) {
    console.log('No NTLM authentication required. Request successful.');
    console.log('Response body:', response1.body.toString().substring(0, 100) + '...');
  } else {
    console.error('Initial request failed or NTLM not initiated. Status:', response1.statusCode);
  }
}

function sendHttpRequest(url, method, headers) {
  return new Promise((resolve, reject) => {
    const client = http.request(url, { method, headers }, (res) => {
      let body = [];
      res.on('data', (chunk) => body.push(chunk));
      res.on('end', () => {
        resolve({ statusCode: res.statusCode, headers: res.headers, body: Buffer.concat(body) });
      });
    });
    client.on('error', reject);
    client.end();
  });
}

performNtlmHandshake().catch(console.error);