LDAP Authentication Example for Internal Web Apps

Sign users in with an LDAPS bind, map directory groups to app roles and fail safely when the directory is down.

Owner: Jonas LindqvistBusiness SystemsContact ownerAdded 2 Sep 2026Updated 30 Sep 2026
  • Runs out of the box: yes
  • Tests: yes
  • CI: yes
  • Docs: yes
  • Used in production: no

Purpose#

A small Node.js web service that authenticates people against a corporate directory. It uses the search-then-bind pattern: a read-only service account finds the user's distinguished name from the login name, then the service binds as that user over LDAPS to verify the password. Nothing about the password is stored.

After a successful bind the service reads the user's group memberships and maps them to three application roles (viewer, editor, admin). Failed binds, locked accounts and an unreachable directory each produce a distinct audit event but the same generic message on the login form.

What you will learn#

  1. Explain why search-then-bind is preferred over building a user DN from the login name
  2. Configure an LDAPS connection with certificate verification and sensible timeouts
  3. Map directory groups to application roles in one reviewed table
  4. Return one generic login error while logging the precise failure reason

Media#

Technologies & features#

Technologies
TypeScriptNode.jsLDAPActive DirectoryDocker Compose
Features
LDAP AuthenticationRole-Based Access ControlAudit Logging
Topics
Directory IntegrationprimaryAccess Control

Lessons learned#

  • Worked

    A separate read-only service account for the DN lookup meant user binds never had to carry search permissions, and revoking the service account was a one-line change.

  • Didn’t work

    Building the DN as uid=<login>,ou=people failed for users who typed their UPN. Searching on both the login name and the UPN fixed it.

  • Decision

    Group membership is cached for five minutes per session. Shorter caches loaded the directory; longer ones delayed role removals.

  • Limitation

    Nested groups are not expanded. Roles come from direct membership only, so teams must add people to the mapped groups themselves.

Try it#

Shell
git clone https://git.example.internal/business-systems/ldap-auth-example.git
cd ldap-auth-example
docker compose up --build

The compose file starts a demo directory seeded with three accounts. Open http://localhost:3000 and sign in as demo.editor with the password from demo/README.md.

Commands come from the owner’s README. Credentials are never stored here.

Resources#

Contributes to

StatusReference
OwnerJonas Lindqvist
TeamBusiness Systems
Last commit28 Sep 2026
Slugldap-authentication-example
Report a problem to the owner