npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@verdaccio/auth-ldap

v1.3.0

Published

LDAP / Active Directory authentication plugin for Verdaccio

Downloads

403

Readme

@verdaccio/auth-ldap

LDAP / Active Directory authentication plugin for Verdaccio.

Authenticates users against an LDAP directory (OpenLDAP, Active Directory, FreeIPA, etc.) and provides group-based access control using LDAP groups.

Requirements

  • Node.js >= 24
  • Verdaccio >= 6.x
  • LDAP server — OpenLDAP, Active Directory, FreeIPA, 389 Directory Server, etc.

Installation

npm install @verdaccio/auth-ldap

Configuration

Add to your Verdaccio config.yaml. Since this is a scoped package, use the full package name as the auth key:

auth:
  '@verdaccio/auth-ldap':
    # Connection
    url: ldap://ldap.example.com:389 # ldaps:// for TLS
    baseDN: ou=users,dc=example,dc=com # base DN for user searches
    bindDN: cn=readonly,dc=example,dc=com # service account for searching (optional)
    bindCredentials: readonly-password # service account password

    # User search
    searchFilter: '(uid={{username}})' # filter to find user (default: (uid={{username}}))
    usernameAttribute: uid # attribute containing username (default: uid)

    # Group search (optional — enables group-based authorization)
    groupSearchBase: ou=groups,dc=example,dc=com
    groupSearchFilter: '(memberUid={{username}})' # filter to find groups (default: (memberUid={{username}}))
    groupAttribute: cn # attribute containing group name (default: cn)

    # Group mapping (optional — map LDAP group names to friendly names)
    groupMapping:
      'cn=npm-developers,ou=groups,dc=example,dc=com': developers
      'cn=npm-admins,ou=groups,dc=example,dc=com': admins

    # Connection options
    reconnect: true # auto-reconnect (default: true)
    timeout: 5000 # operation timeout in ms (default: 5000)
    connectTimeout: 10000 # connection timeout in ms (default: 10000)

    # TLS options (for ldaps://)
    tlsOptions:
      rejectUnauthorized: true # set to false for self-signed certs

Active Directory configuration

auth:
  '@verdaccio/auth-ldap':
    url: ldap://dc01.corp.example.com:389
    baseDN: ou=Users,dc=corp,dc=example,dc=com
    bindDN: cn=svc-verdaccio,ou=ServiceAccounts,dc=corp,dc=example,dc=com
    bindCredentials: LDAP_BIND_PASSWORD
    searchFilter: '(sAMAccountName={{username}})'
    usernameAttribute: sAMAccountName
    groupSearchBase: ou=Groups,dc=corp,dc=example,dc=com
    groupSearchFilter: '(member={{dn}})'
    groupAttribute: cn

Environment variable substitution

Config values can reference environment variables by name:

auth:
  '@verdaccio/auth-ldap':
    url: LDAP_URL
    baseDN: LDAP_BASE_DN
    bindDN: LDAP_BIND_DN
    bindCredentials: LDAP_BIND_PASSWORD
    groupSearchBase: LDAP_GROUP_SEARCH_BASE

Package access examples

Example 1: Verdaccio packages open, popular packages restricted to admins

Scoped @verdaccio/* packages are accessible to all authenticated users, but popular packages like react, jquery, and express are restricted to the admins LDAP group:

packages:
  # Verdaccio packages — open to all authenticated users
  '@verdaccio/*':
    access: $authenticated
    publish: $authenticated
    proxy: npmjs

  # Popular packages — only admins can publish/unpublish
  'react':
    access: $authenticated
    publish: admins
    unpublish: admins
    proxy: npmjs
  'jquery':
    access: $authenticated
    publish: admins
    unpublish: admins
    proxy: npmjs
  'express':
    access: $authenticated
    publish: admins
    unpublish: admins
    proxy: npmjs

  # Scoped company packages — developers can publish, admins can unpublish
  '@company/*':
    access: $authenticated
    publish: developers
    unpublish: admins

  # Everything else — read from npmjs, only admins can publish
  '**':
    access: $authenticated
    publish: admins
    proxy: npmjs

Example 2: Public read, restricted write

Anyone can install packages, but only specific LDAP groups can publish:

packages:
  '@internal/*':
    access: $authenticated
    publish: developers
    unpublish: admins
  '**':
    access: $all
    publish: admins
    proxy: npmjs

Example 3: Team-based access

Different teams own different scopes:

packages:
  '@frontend/*':
    access: $authenticated
    publish: frontend-team
    unpublish: admins
  '@backend/*':
    access: $authenticated
    publish: backend-team
    unpublish: admins
  '@infra/*':
    access: devops
    publish: devops
    unpublish: admins
  '**':
    access: $authenticated
    publish: admins
    proxy: npmjs

Logging in

Basic login

npm login --registry http://localhost:4873
# Username: your-ldap-username
# Password: your-ldap-password

Login as admin (OpenLDAP example)

First, ensure an admin user and group exist in LDAP:

# Create the admins group (if it doesn't exist)
ldapadd -x -H ldap://localhost:389 \
  -D "cn=admin,dc=verdaccio,dc=org" -w admin <<EOF
dn: cn=admins,ou=groups,dc=verdaccio,dc=org
objectClass: posixGroup
cn: admins
gidNumber: 3000
memberUid: adminuser
EOF

# Create an admin user
ldapadd -x -H ldap://localhost:389 \
  -D "cn=admin,dc=verdaccio,dc=org" -w admin <<EOF
dn: uid=adminuser,ou=users,dc=verdaccio,dc=org
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: Admin User
sn: Admin
uid: adminuser
uidNumber: 1100
gidNumber: 1100
homeDirectory: /home/adminuser
userPassword: adminpassword
mail: [email protected]
EOF

Then login:

npm login --registry http://localhost:4873
# Username: adminuser
# Password: adminpassword

The plugin will authenticate against LDAP, find that adminuser is a member of the admins group, and grant the corresponding permissions.

Login as admin (Active Directory example)

npm login --registry http://localhost:4873
# Username: admin.user          (sAMAccountName)
# Password: your-ad-password

The plugin uses the sAMAccountName attribute (configured via searchFilter) to find the user, then checks AD group membership via the member attribute.

Verify your groups

After logging in, publish a test package to verify your permissions:

# Create a minimal test package
mkdir /tmp/test-pkg && cd /tmp/test-pkg
npm init -y --scope=@company
npm publish --registry http://localhost:4873

# If you get "publish not allowed", your user doesn't have the required group
# Enable debug logging to see which groups were returned:
# DEBUG=verdaccio:plugin* verdaccio --config config.yaml

Using auth tokens in CI/CD

# Login once to get a token
npm login --registry http://your-verdaccio:4873

# The token is stored in ~/.npmrc — extract it for CI:
grep "_authToken" ~/.npmrc

# In CI, set the token directly:
npm config set //your-verdaccio:4873/:_authToken "YOUR_TOKEN"
npm publish --registry http://your-verdaccio:4873

Environment variables reference

| Variable | Required | Description | | ------------------------ | -------- | ------------------------------------------- | | LDAP_URL | Yes | LDAP server URL (ldap:// or ldaps://) | | LDAP_BASE_DN | Yes | Base DN for user searches | | LDAP_BIND_DN | No | Service account DN for searching | | LDAP_BIND_PASSWORD | No | Service account password | | LDAP_GROUP_SEARCH_BASE | No | Base DN for group searches | | DEBUG | No | Set to verdaccio:plugin* for debug output |

Available debug namespaces:

  • verdaccio:plugin:ldap — authentication and authorization decisions
  • verdaccio:plugin:ldap:client — LDAP bind, search, and connection events
  • verdaccio:plugin:ldap:config — config value resolution from env vars

How It Works

Authentication Flow

npm login (username + password)
         │
         ▼
   LdapAuthPlugin.authenticate()
         │
    ┌────┴────────────────────────────┐
    │                                 │
    ▼                                 │
 1. Bind with service account         │
    (for user search)                 │
         │                            │
         ▼                            │
 2. Search for user DN                │
    (uid={{username}})                 │
         │                            │
         ▼                            │
 3. Bind with user DN + password      │
    (verify credentials)              │
         │                            │
         ▼                            │
 4. Search for user groups            │
    (memberUid={{username}})           │
         │                            │
         ▼                            │
 5. Return groups → Verdaccio         │
    ┌────┴────┐                       │
    │         │                       │
allow_access  allow_publish           │
    │         │                       │
    ▼         ▼                       │
 Check user groups vs                 │
 package config                       │
                                      │
              LDAP Server ◄───────────┘

Architecture

                   +-----------+
                   | Verdaccio |
                   +-----+-----+
                         |
                  LdapAuthPlugin
                         |
              ┌──────────┴──────────┐
              │                     │
        authenticate()        allow_access/publish()
              │                     │
         LDAP Server           Group check
    ┌─────────────────┐    (user.groups ∩ pkg.access)
    │ 1. bind (svc)   │
    │ 2. search user  │
    │ 3. bind (user)  │
    │ 4. search groups│
    └─────────────────┘

Migrating from verdaccio-ldap

If you are currently using the older verdaccio-ldap plugin, you can switch to @verdaccio/auth-ldap with minimal configuration changes. The new plugin accepts the legacy config format and automatically normalizes it at startup, emitting deprecation warnings for each legacy property so you can update at your own pace.

Quick migration

  1. Replace the package:
npm uninstall verdaccio-ldap
npm install @verdaccio/auth-ldap
  1. Your existing config.yaml will work as-is. On startup you will see deprecation warnings guiding you to the new property names.

What gets migrated automatically

| Legacy property (verdaccio-ldap) | New property (@verdaccio/auth-ldap) | | ---------------------------------- | ----------------------------------- | | client_options.url | url | | client_options.searchBase | baseDN | | client_options.adminDn | bindDN | | client_options.adminPassword | bindCredentials | | client_options.searchFilter | searchFilter | | client_options.groupSearchBase | groupSearchBase | | client_options.groupSearchFilter | groupSearchFilter | | client_options.groupDnProperty | groupAttribute | | client_options.reconnect | reconnect | | groupNameAttribute | groupAttribute | | {{dn}} in groupSearchFilter | {{username}} | | env var LDAP_ADMIN_PASS | bindCredentials |

The following legacy options are dropped with a warning since they are no longer needed:

  • cache — Verdaccio handles session management
  • searchAttributes — the plugin requests only the attributes it needs
  • type: ldap — removed silently

Configuration before and after

Before (verdaccio-ldap):

auth:
  ldap:
    type: ldap
    groupNameAttribute: cn
    cache:
      size: 100
      expire: 300
    client_options:
      url: ldap://ldap.example.com
      adminDn: cn=admin,dc=example,dc=com
      adminPassword: admin
      searchBase: ou=People,dc=example,dc=com
      searchFilter: '(uid={{username}})'
      groupDnProperty: cn
      groupSearchBase: ou=groups,dc=example,dc=com
      groupSearchFilter: '(memberUid={{dn}})'
      searchAttributes: ['*', 'memberOf']
      reconnect: true

After (@verdaccio/auth-ldap — recommended):

auth:
  '@verdaccio/auth-ldap':
    url: ldap://ldap.example.com
    baseDN: ou=People,dc=example,dc=com
    bindDN: cn=admin,dc=example,dc=com
    bindCredentials: admin
    searchFilter: '(uid={{username}})'
    groupAttribute: cn
    groupSearchBase: ou=groups,dc=example,dc=com
    groupSearchFilter: '(memberUid={{username}})'
    reconnect: true

Both configurations produce identical behavior. The "before" format will continue to work but will emit deprecation warnings on startup.

New features in @verdaccio/auth-ldap

These features are not available in the old plugin:

  • Group mapping — map LDAP group DNs to friendly names via groupMapping
  • Environment variable substitution — any config value can reference an env var by name
  • Explicit access controlallow_access, allow_publish, and allow_unpublish with support for $all, $authenticated, and $anonymous tokens
  • Configurable timeoutstimeout and connectTimeout options
  • TLS options — explicit tlsOptions.rejectUnauthorized for self-signed certificates

Development

See LOCAL_DEV.md for the full local development guide, including:

  • Setup, build, test, and lint commands
  • Running Verdaccio + OpenLDAP via Docker Compose
  • Pre-seeded test users and groups
  • Inspecting LDAP data with ldapsearch
  • Debug logging namespaces

License

MIT