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

@vanishcode/verdaccio-admin-users

v0.1.0

Published

Verdaccio middleware plugin: admin UI for managing htpasswd users and packages access rules

Downloads

113

Readme

verdaccio-admin-users

A Verdaccio middleware plugin that adds an admin web UI for managing htpasswd users and packages: access rules — without hand-editing htpasswd or config.yaml.

Features

  • List, add, delete, and reset-password htpasswd users.
  • View and edit the packages: access rules block of config.yaml.
  • React + Vite SPA mounted at /-/admin/.
  • Reuses Verdaccio's web-UI JWT for auth; gates admin actions by an explicit allow-list and/or group membership.
  • Built-in defenses: per-IP rate limit, optional IP allow-list, password length policy, audit log of every write action.

Install

pnpm add verdaccio-admin-users

In config.yaml:

auth:
  htpasswd:
    file: ./htpasswd
    max_users: -1                # IMPORTANT: disables `npm adduser` self-signup;
                                 # new users can ONLY be created via the admin UI.

middlewares:
  admin-users:
    enabled: true
    admin_group: admin           # optional; default "admin"
    admins: [alice]              # explicit admin allow-list (recommended)

    # ─── Security knobs (all optional; defaults shown) ───
    min_password_length: 8       # admin-set passwords must be at least this long
    rate_limit:
      window_ms: 900000          # 15 minutes
      max: 100                   # max requests per IP per window
    # rate_limit: false          # set to false to disable rate limiting entirely
    # allowed_ips:               # if set, only these IPs may reach /-/admin/*
    #   - 127.0.0.1
    #   - 10.0.0.42

Then visit http://localhost:4873/-/admin/. The SPA reads the JWT that the main UI stores in localStorage, so log in via the main UI first.

Endpoints

All under /-/admin/api/. Require an authenticated request from a user listed in admins or carrying the admin_group group.

| Method | Path | Body | | ------ | ----------------------------- | -------------------------- | | GET | /me | — | | GET | /users | — | | POST | /users | { name, password } | | DELETE | /users/:name | — | | POST | /users/:name/reset-password | { password } | | GET | /packages | — | | PUT | /packages | full new packages: block | | GET | /uplinks | — |

Security model

| Layer (in order requests are checked) | What it does | | ------------------------------------- | ------------ | | allowed_ips allow-list (optional) | Reject 403 if the client IP isn't whitelisted | | rate_limit per-IP throttle | 429 once a single IP exceeds the window quota — applies to all /-/admin/* traffic, authenticated or not | | Verdaccio web JWT validation | 401 if no/expired/invalid token (reuses webUIJWTmiddleware) | | requireAdmin allow-list / group | 403 if the authenticated user isn't an admin | | min_password_length policy | 400 on add/reset if the new password is too short | | Username length cap (64 chars) | 400 on add/delete/reset if the username is longer | | Password length cap (72 UTF-8 bytes) | 400 on add/reset — bcrypt silently truncates past 72 bytes, so anything longer is misleading | | bcrypt_rounds clamp (8–14) | Out-of-range values in config are coerced and a warning is logged at startup | | Audit log | Every add/delete/reset/save emits a warn log line with actor, ip, action, target, outcome — successes AND failures (invalid input, conflict, not found, error) |

Recommended setup

  1. Disable npm adduser self-signup by setting auth.htpasswd.max_users: -1. Otherwise an attacker can register their own account regardless of what this plugin does. Once disabled, the only way to create a new user is via the admin UI.
  2. Run Verdaccio behind a TLS reverse proxy (nginx/caddy/Traefik). The Bearer JWT travels in plaintext — TLS is non-negotiable for any non-localhost setup. Set server.trustProxy so req.ip reflects the real client IP for the rate limiter and allowed_ips.
  3. Don't bind to 0.0.0.0 if you only need localhost. listen: 127.0.0.1:4873 is fine for a developer-only setup. Otherwise rely on a firewall / VPC security group to restrict the network.
  4. Pin a real secret: in config.yaml (a long random string). Otherwise Verdaccio regenerates one on each restart and invalidates all tokens — and worse, may default to predictable values in misconfigured deployments.
  5. Set userRateLimit: at the top level of config.yaml to throttle /-/verdaccio/sec/login, which is outside this plugin and is the natural target for password brute-forcing:
    userRateLimit:
      windowMs: 900000   # 15 min
      max: 20
  6. Watch the audit log. Every admin write emits a line like:
    warn --- admin-users audit: alice from 10.0.0.5 did add_user (target=bob)
    Ship those lines to whatever you use for security monitoring. Anomalies look like high-rate add_user / reset_password actions, or activity from unfamiliar IPs.
  7. Treat the admin's password like a secret. Use a password manager and a long random string. The bcrypt cost factor is 10 by default — fine, but any leaked password file with a weak password will be cracked offline quickly.

What this plugin does not protect against

  • A stolen JWT being replayed before its exp runs out (default Verdaccio JWT lifetime). Mitigate via short JWT expiry, TLS, and not pasting tokens into untrusted contexts.
  • XSS in the main Verdaccio UI exfiltrating localStorage.token. The token is reused by this SPA, so any XSS in either UI is a full takeover. Don't install untrusted theme plugins.
  • Disk-level access to htpasswd (the bcrypt hashes) or config.yaml (your packages rules). Use OS-level file permissions and run Verdaccio under a dedicated unprivileged user.
  • Plugin-config tampering. Only packages: is rewritten by the plugin. Other sections must still be edited by hand and the operator should treat config.yaml as a sensitive file.

Caveats

  • Editing the packages block via the UI rewrites config.yaml with js-yaml. Comments are not preserved. A config.yaml.bak backup is created before the first write.
  • The plugin only manipulates the packages: section. All other config (auth, middlewares, web, etc.) stays manual.
  • htpasswd-authenticated users have no native group concept beyond [username, $authenticated, $all]. Use the admins: allow-list rather than admin_group: unless you have a custom auth plugin that returns groups.
  • Newly-created users are hashed with bcrypt regardless of the algorithm configured for the htpasswd auth plugin.

License

MIT