express-basic-auth

Plug-and-play HTTP Basic Auth middleware for Express, with static users, custom authorizers, and timing-safe comparisons.

Library
npm
v1.2.1
334stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
37/100Needs Attention
Development Activity0
Maintenance20
Community48
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
74/100Good
Architecture78
Code Quality72
Innovation55
Learning Curve90

express-basic-auth is a small, focused Express middleware that adds HTTP Basic Authentication to any route or app in a single line. Rather than hand-rolling header parsing and credential comparison, developers pass a users map of username/password pairs (or a custom authorizer function) and the middleware handles parsing the Authorization header, checking credentials, and responding with a 401 challenge when they don’t match.

The library is deliberately narrow in scope: it wraps the battle-tested basic-auth package for header parsing and adds its own timing-safe safeCompare helper (built on Node’s crypto.timingSafeEqual) so that credential checks aren’t vulnerable to timing attacks — a detail many hand-rolled implementations get wrong. It supports both synchronous and asynchronous custom authorizers, configurable unauthorized response bodies (string, JSON, or a function of the request), and an optional WWW-Authenticate challenge header with a static or dynamic realm.

It ships with a bundled TypeScript declaration file, so no separate @types package is needed, and an example.js that doubles as a runnable demo and the basis of its Mocha/Supertest test suite. It’s commonly used to quickly password-protect internal tools, admin dashboards, health-check endpoints, or staging environments where a full authentication system would be overkill.

What You Get

  • Drop-in Express middleware activated with app.use(basicAuth({ ... })) — no route-by-route wiring required
  • Static users credential map for simple username/password gating
  • Custom authorizer function support, both synchronous and asynchronous (via a Node-style callback)
  • A safeCompare helper using crypto.timingSafeEqual to avoid timing-attack vulnerabilities in credential checks
  • Configurable unauthorized response body — static string, JSON object, or a function of the request
  • Optional WWW-Authenticate challenge header with a static or per-request dynamic realm, so browsers prompt for credentials
  • Bundled TypeScript declaration file — works out of the box in TS projects with no separate @types install

Common Use Cases

  • Password-protecting an internal admin dashboard or staging environment behind a single shared credential
  • Gating a health-check or metrics endpoint so it isn’t publicly readable
  • Quickly prototyping an authenticated API before a full auth system (OAuth, sessions, JWT) is built
  • Restricting access to a demo or preview deployment shared with a small group of collaborators
  • Adding a lightweight auth layer to a webhook receiver or internal microservice endpoint

Under The Hood

Architecture The entire middleware lives in a single index.js file structured as one factory function, buildMiddleware(options), that closes over configuration (users map, authorizer, challenge flag, response-body and realm resolvers) and returns the actual Express middleware function. Internally it normalizes optional callback-style options (unauthorizedResponse, realm) into functions via an ensureFunction helper so the request-handling code can always call them uniformly, whether the caller passed a static value or a function. The request path is a single linear flow: parse the Authorization header via the basic-auth package, attach req.auth, branch on synchronous vs. asynchronous authorizer, and call next() or emit a 401 with an optional challenge header. There is no internal state, no class hierarchy, and no dependency injection — the whole module is one exported function plus a safeCompare static, making the blast radius of any change trivially small.

Tech Stack The runtime dependency surface is minimal: only basic-auth (^2.0.1) for header parsing, plus Node’s built-in crypto and assert modules. It targets Express (peer usage, not a listed dependency) via the standard (req, res, next) middleware signature. Development tooling uses Mocha for the test runner, Supertest for HTTP-level integration assertions against a real Express app, should for BDD-style assertions, and TypeScript (^2.9.2) solely to typecheck the bundled .d.ts declaration file via tsc — there’s no build step or transpilation for the library itself, which ships as plain CommonJS JavaScript.

Code Quality The test suite in test.js is comprehensive for the module’s scope: it spins up a real Express app with one route per configuration variant (static users, custom sync authorizer, custom async authorizer, custom response bodies, challenge headers, static and dynamic realms) and exercises each via Supertest, covering both accept and reject paths. safeCompare itself has dedicated unit tests for equal, different-length, and prefix-matching inputs — important given its security role. Error handling is deliberately minimal (an assert on malformed options, assert.ifError on async authorizer errors) rather than typed or wrapped, consistent with the module’s small surface area. Naming is plain and consistent (camelCase functions, descriptive option names), and CI is configured via CircleCI to run the Mocha suite plus the declaration-file typecheck on every push.

What Makes It Unique The library’s distinguishing choice is treating timing-attack resistance as a first-class concern for a basic-auth middleware, rather than an afterthought: it exposes safeCompare as a public API specifically so custom authorizers can avoid falling back to ==/=== string comparison, and it documents the bitwise-operator (&/|) requirement for combining boolean checks without short-circuit timing leaks. Most comparable basic-auth middlewares in the ecosystem either omit this protection entirely or bury it as an internal implementation detail rather than a documented, reusable primitive for consumers writing their own authorizers.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search