{"id":11231,"library":"ldapauth-fork","title":"Node.js LDAP Authentication Fork","description":"ldapauth-fork is a Node.js library for authenticating users against an LDAP server. It's a maintained fork of the original `node-ldapauth` package, primarily created to integrate newer versions of `ldapjs`, enable `tlsOptions` support, and address various community-reported issues. The package provides a robust API for user authentication, including support for group membership checks and configurable search filters. It ships with TypeScript type definitions since v4.0.0 and utilizes Bunyan for logging, aligning with `ldapjs`'s logging approach. The current stable version is 6.1.0, with a release cadence that addresses bug fixes, dependency updates, and new features, indicating active maintenance. Key differentiators include its explicit support for modern `ldapjs` versions, comprehensive configuration options for diverse LDAP setups, and improved error handling through `EventEmitter` inheritance.","status":"active","version":"6.1.0","language":"javascript","source_language":"en","source_url":"git://github.com/vesse/node-ldapauth-fork","tags":["javascript","authenticate","ldap","authentication","auth","typescript"],"install":[{"cmd":"npm install ldapauth-fork","lang":"bash","label":"npm"},{"cmd":"yarn add ldapauth-fork","lang":"bash","label":"yarn"},{"cmd":"pnpm add ldapauth-fork","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core LDAP client library for all communication with the LDAP server.","package":"ldapjs","optional":false},{"reason":"Used for structured logging within the library and passed through to ldapjs.","package":"bunyan","optional":true}],"imports":[{"note":"Since v4.0.0, TypeScript types are provided. The library is typically used with a default export for the LdapAuth class. Ensure your Node.js version (>=16.14.0) and project configuration support ESM if using `import` syntax.","wrong":"const LdapAuth = require('ldapauth-fork').default; // Incorrect if the main export is a default export, often LdapAuth is the default.\nimport { LdapAuth } from 'ldapauth-fork/dist/LdapAuth';","symbol":"LdapAuth","correct":"import LdapAuth from 'ldapauth-fork'; // ESM\nimport { LdapAuth } from 'ldapauth-fork'; // For explicit named import if package.json exports it as such or if a specific configuration requires it."},{"note":"This is a type import for configuring the LdapAuth constructor. It's available since v4.0.0 when TypeScript types were introduced.","wrong":"import { LdapAuthOptions } from 'ldapauth-fork'; // Using 'type' keyword for types is best practice.","symbol":"LdapAuthOptions","correct":"import type { LdapAuthOptions } from 'ldapauth-fork';"},{"note":"This is the standard CommonJS pattern shown in the README. The primary `LdapAuth` class is exported as the module default.","wrong":"const { LdapAuth } = require('ldapauth-fork'); // Incorrect if LdapAuth is the default export.\nconst auth = new require('ldapauth-fork')(options); // Less readable and not idiomatic.","symbol":"CommonJS require","correct":"const LdapAuth = require('ldapauth-fork');"}],"quickstart":{"code":"import LdapAuth, { LdapAuthOptions } from 'ldapauth-fork';\nimport type { User } from 'ldapjs';\n\nconst options: LdapAuthOptions = {\n  url: process.env.LDAP_URL ?? 'ldaps://localhost:636',\n  bindDN: process.env.LDAP_BIND_DN ?? 'cn=admin,dc=example,dc=org',\n  bindCredentials: process.env.LDAP_BIND_CREDENTIALS ?? 'adminsecret',\n  searchBase: process.env.LDAP_SEARCH_BASE ?? 'ou=users,dc=example,dc=org',\n  searchFilter: process.env.LDAP_SEARCH_FILTER ?? '(uid={{username}})',\n  log: console // Simple logger, use a Bunyan instance in production\n};\n\nasync function authenticateUser(username: string, password: string): Promise<User | null> {\n  const auth = new LdapAuth(options);\n\n  auth.on('error', (err) => {\n    console.error(`LDAP Authentication Error: ${err.message}`);\n  });\n\n  try {\n    console.log(`Attempting to authenticate user: ${username}`);\n    const user = await new Promise<User | null>((resolve, reject) => {\n      auth.authenticate(username, password, (err, user) => {\n        if (err) {\n          console.error(`Authentication failed for ${username}: ${err.message}`);\n          return reject(err);\n        }\n        if (user) {\n          console.log(`User ${username} authenticated successfully.`);\n          resolve(user as User);\n        } else {\n          console.log(`Authentication failed: No user found for ${username}.`);\n          resolve(null);\n        }\n      });\n    });\n    return user;\n  } catch (error) {\n    console.error('An unexpected error occurred during authentication:', error);\n    return null;\n  } finally {\n    await new Promise<void>((resolve, reject) => {\n      auth.close((err) => {\n        if (err) return reject(err);\n        resolve();\n      });\n    });\n    console.log('LDAP connection closed.');\n  }\n}\n\n// Example usage:\nauthenticateUser('testuser', 'testpassword')\n  .then(user => {\n    if (user) {\n      console.log('Authenticated User Details:', user);\n    }\n  })\n  .catch(console.error);\n","lang":"typescript","description":"This quickstart demonstrates how to instantiate `LdapAuth`, authenticate a user with a username and password, handle errors, and close the LDAP connection using modern async/await syntax. It utilizes environment variables for sensitive configuration options and shows basic error logging. A simple `console` logger is used, but a Bunyan instance is recommended for production."},"warnings":[{"fix":"Remove the `includeRaw` property from your `LdapAuthOptions` configuration. Data previously retrieved via `includeRaw` is no longer available directly through this option.","message":"The `includeRaw` option has been removed from `LdapAuth` configuration. This is due to its removal from the underlying `ldapjs` library in its v3.x upgrade.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Review `ldapjs` v3.x changelog for any breaking changes that might indirectly affect your application's interaction with the LDAP server or how `ldapjs` options are interpreted. Test thoroughly after upgrade.","message":"Major version update of the underlying `ldapjs` library to v3.0.4. While `ldapauth-fork` attempts to abstract these changes, direct interaction with `ldapjs` options or behaviors might be affected.","severity":"breaking","affected_versions":">=6.0.0"},{"fix":"Applications should now listen for 'error' events on the `LdapAuth` instance using `auth.on('error', handler)` to properly catch and handle errors originating from the LDAP client or authentication process. Previous error handling mechanisms might no longer be sufficient.","message":"The `LdapAuth` class now inherits from `EventEmitter`. This changes how errors are propagated, specifically re-emitting `ldaps` errors.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"If you were relying on internal logging, you should now provide a Bunyan logger instance via the `log` option in `LdapAuthOptions`. Logs will be emitted at TRACE-level under component:ldapauth. Adjust your logging configuration accordingly.","message":"The tracing module was changed from an unspecified prior logger to [Bunyan](https://github.com/trentm/node-bunyan). The logger instance is now passed forward to `ldapjs`.","severity":"breaking","affected_versions":">=4.0.0"},{"fix":"Always ensure `searchBase` is correctly configured with a valid LDAP distinguished name (DN) where user accounts are located. Verify that the `searchFilter` correctly uses `{{username}}` to interpolate the provided username.","message":"The `searchBase` option, while optional in some contexts, is critical for defining where user searches begin. Providing an empty string or an invalid `searchBase` can lead to authentication failures.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure `LdapAuth` is correctly imported as the default export using `const LdapAuth = require('ldapauth-fork');` for CommonJS or `import LdapAuth from 'ldapauth-fork';` for ESM, then instantiate it with `new LdapAuth(options);`.","cause":"Attempting to call `authenticate` on an uninitialized or incorrectly imported `LdapAuth` instance, often due to incorrect CommonJS `require` syntax.","error":"TypeError: auth.authenticate is not a function"},{"fix":"Verify the `url` in your `LdapAuthOptions` is correct and reachable. Check network connectivity between your application and the LDAP server. The `connectTimeout` option in `ldapjs` (which can be passed via `ldapauth-fork` options) can be adjusted if the server is slow to respond, though excessive timeouts may mask underlying issues.","cause":"The LDAP server did not respond within the configured connection timeout period, indicating network issues, an incorrect LDAP URL, or a non-responsive server.","error":"Error: Connect Timeout (ldapauth-fork)"},{"fix":"Double-check the `bindDN` and `bindCredentials` in your `LdapAuthOptions`. Ensure the user specified by `bindDN` has sufficient read permissions on the `searchBase` to find user entries. If no `bindDN` is provided, ensure your LDAP server allows anonymous binds for searches.","cause":"This typically means the `bindDN` and `bindCredentials` provided for the admin user (if configured) are incorrect or lack the necessary permissions to perform the `searchBase` lookup.","error":"LdapAuth: Error: [LDAP_PROTOCOL_ERROR] 00000000: LdapErr: DSID-0C090C5D, comment: In order to perform this operation a successful bind must be completed on the connection."}],"ecosystem":"npm"}