A few things that are fine to skip while prototyping against a local test directory become important before ldapjs code reaches production.
Never bind with a real password over plain ldap://. Use ldaps:// (see LDAPS and TLS), and confirm tlsOptions isn't disabling verification:
Danger
// Never ship this:
const client = ldap.createClient({
url: "ldaps://dc1.example.com:636",
tlsOptions: { rejectUnauthorized: false },
});
rejectUnauthorized: false accepts any certificate, including one from an attacker performing a man-in-the-middle attack. It's sometimes used temporarily against a self-signed local test server — never in a deployed environment.
Instead, trust the specific CA certificate your directory uses:
const client = ldap.createClient({
url: "ldaps://dc1.example.com:636",
tlsOptions: {
ca: [fs.readFileSync(process.env.LDAP_CA_CERT_PATH!)],
},
});
Escape every value that comes from outside your code before it goes into a filter or a DN — see LDAP injection. This applies to usernames, emails, and anything else a user can influence.
Service account credentials belong in environment variables or a secrets manager, not hardcoded or committed:
const client = ldap.createClient({ url: process.env.LDAP_URL! });
client.bind(process.env.LDAP_BIND_DN!, process.env.LDAP_BIND_PASSWORD!, callback);
Without a timeout and connectTimeout, a request against an unreachable or overloaded directory server can hang indefinitely, tying up whatever handled the incoming request. Set both explicitly (see Connecting) and make sure your application has a fallback path for when LDAP is unavailable.
A long-lived client can emit error events unrelated to any specific request — an unhandled error event on an EventEmitter crashes the Node process. Always attach a listener, as shown in Getting started with ldapjs.
The service account used for searching should have read-only access scoped to what it actually needs, not a domain administrator account. If that account's credentials ever leak, the blast radius should be limited to directory reads.
- [ ] Connections use
ldaps://or STARTTLS, never plain LDAP with real credentials. - [ ]
rejectUnauthorizedis not disabled, and the correct CA certificate is trusted. - [ ] Every filter value and DN built from user input is escaped.
- [ ] Bind credentials come from environment variables or a secrets manager.
- [ ]
timeoutandconnectTimeoutare set. - [ ] The client's
errorevent is handled. - [ ] The service account has least-privilege, read-only access.
If you're specifically targeting Active Directory, continue to Active Directory for the deeper conceptual background behind the Active Directory integration page.