Library / SDK
jshttp/basic-auth avatar
jshttp/basic-auth

basic-auth parses one header field and stays under a kilobyte

Generic basic auth Authorization header field parser

716 stars91 forksTypeScriptMIT

At a glance

What is it?
basic-auth is a TypeScript module that turns a Basic authorization header into a name and pass pair, and back again. It is small, MIT licensed and maintained, and the only real trap is that version 3 is ESM while the documented examples still use require.
Who is it for?
Adopt basic-auth if you are writing a Node.js server that has to read a Basic authorization header and you want one audited implementation instead of an ad hoc base64 split. Do not adopt it if you need to authenticate the user, since this module only parses credentials and the comparison against your user store is your job, and do not copy the require based examples into an ESM project without checking the module format.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One header field, parsed and formatted

The scope is deliberately tiny. The project describes itself as a generic basic auth Authorization header field parser for whatever, and the API is two functions. parse(string) takes a Basic auth authorization header string and returns an object with name and pass properties, or undefined if the string is invalid. format(credentials) takes a credentials object with name and pass and returns the header string. There is no user store, no realm handling, no challenge generation, no session logic. The module is the parsing step, nothing more. That is the point of it: a Basic header is base64 of a name and a colon separated password, and everyone who needs to read one ends up writing that decoding by hand, usually slightly differently, usually in more than one place in a codebase. The audience is Node.js server authors who need that one field handled consistently, and the fact that the package is maintained by the jshttp organisation, the same group behind well known Node HTTP middleware, is the signal about the level of care involved.

How parse and format behave at the edges

The behaviour is easy to read from the examples. The module is installed from the npm registry with the standard npm install command:

bash
$ npm install basic-auth

Parsing returns undefined for anything that is not a valid Basic header, so a caller must handle the failure case rather than assume a result. The documented usage shows the typical server path:

js
const { parse } = require('basic-auth');
const user = parse(req.headers.authorization ?? '');
// => { name: 'something', pass: 'whatever' }

The nullish coalescing to an empty string matters, because an absent header is the common case and parse has to receive a string. The same function works on any header that carries a Basic value, and the documentation gives a second example using a Proxy-Authorization header fetched with req.getHeader, which is a detail that catches people out when a proxy sits in front of the application. Formatting is the inverse:

js
const { format } = require('basic-auth');
const credentials = { name: 'foo', pass: 'bar' };
const authHeader = format(credentials);
// => "Basic Zm9vOmJhcg=="

The output is the literal word Basic, a space, and the base64 encoding of foo:bar. The API surface is small enough that the whole contract fits in those two examples, which is a good sign for a library you will end up trusting with credentials.

The examples use require, but version 3 is an ES module

Here is the one place where the documentation and the package metadata disagree, and it will cost you an afternoon if you hit it cold. Every example in the project documentation uses CommonJS require, for example `const { parse } = require('basic-auth');`. The package manifest for version 3.0.0 says something different. It sets the type field to module, points the exports map at ./dist/index.js, and the files array ships only the dist/ directory, which is the compiled TypeScript output. The type module field is what makes a .js file an ES module, so the published build is ESM and a plain require of it will not work the way the examples imply. The dependency versions support that reading too, with TypeScript listed at version 7 and Node types at 26. The practical advice is short: if your application is ESM, use an import statement and take the named exports, and if you are still on CommonJS, pin to the 2.x line where the require examples match the published format. Nothing in the documentation calls this out, so treat the manifest as the authority on module format and the code samples as illustrations of the API rather than as drop-in snippets.

Parsing is not authentication, and the difference matters

The example server in the project documentation is worth reading closely because it shows exactly where the module stops. The server parses the header, then compares the result against a check function, and the check function is described as typically being against your user store:

js
const http = require('node:http');
const { parse } = require('basic-auth');
const compare = require('tsscmp');

// Create server
const server = http.createServer(function (req, res) {
  const credentials = parse(req.headers.authorization ?? '');

  // Check credentials
  // The "check" function will typically be against your user store
  if (!credentials || !check(credentials.name, credentials.pass)) {
    res.statusCode = 401;
    res.setHeader('WWW-Authenticate', 'Basic realm="example"');
    res.end('Access denied');
  } else {
    res.end('Access granted');
  }
});

Two things stand out. The comparison uses a separate module, tsscmp, and the comment explains why the code compares both fields without short circuiting, so that a wrong username does not skip the password comparison and leak timing information. And the 401 response sets a WWW-Authenticate header naming the protection space, which is what tells the client to prompt. The module under discussion contributes the parse call and nothing else. Deciding whether the credentials are valid, comparing them in constant time, generating the challenge and choosing a protection space all stay with you.

A kilobyte budget enforced by the build

The repository layout and the scripts tell you how seriously the size is taken. The top level is src/, tests/, benchmarks/, tsconfig.json, tsconfig.build.json and package.json, with a build tool, ts-scripts, handling compilation, formatting, linting, test running and spec generation. There is a size-limit configuration in the manifest, and it is not a suggestion: the path is dist/index.js and the limit is 1 kB. The npm scripts enforce it as part of the test run, since the test script runs the test suite and then the size check, and a separate size script exists for running it alone. That constraint is a good design signal for a credential parsing library, because every dependency is a liability in a code path that touches secrets. It also explains why the module does one thing. The benchmarks directory and the vitest bench script point at the other side of the same discipline, measuring the parse path so a change that makes it slower is visible. The declared Node.js floor for version 3 is 22 or newer, and the manifest is the source of truth for that.

Version 3 came after a long quiet period, and the module system changed with it

The release history explains the compatibility question better than the documentation does. Version 2.0.1 was published in September 2018 and version 2.0.0 in September 2017, so for most of its life this package was a 2.x CommonJS module. Version 3.0.0 arrived on 2026-08-03, which is both the ESM conversion and a jump that lets a semver range express the break cleanly. That is a maintenance signal worth noting in both directions. The repository is not archived and the last push was on 2026-10-12, so the code is being worked on now, roughly two months after the 3.0.0 tag and with the pull request workflow and coverage badges in place. The gap between 2018 and 2026 is the other half of the picture: a package that sat unchanged for years is not a risk in itself, since the code is small, but it does mean the 2.x documentation in your notes and blog posts describes a module format that the current release no longer ships. The licence is MIT, with the licence file kept in the repository root, which is a permissive grant and one of the easiest licences to satisfy in a commercial product.

Editorial conclusion

Adopt basic-auth if you are writing a Node.js server that has to read a Basic authorization header and you want one audited implementation instead of an ad hoc base64 split. Do not adopt it if you need to authenticate the user, since this module only parses credentials and the comparison against your user store is your job, and do not copy the require based examples into an ESM project without checking the module format. Before you depend on it, confirm the import style against the type field in the package manifest, remember that credentials arrive base64 encoded and are not encrypted, and check that the version you install matches the Node.js floor of 22 that version 3 declares.

Frequently asked questions

How do I install the basic-auth Node.js module?

It is published to the npm registry and installed with `npm install basic-auth`. The package manifest declares a Node.js floor of 22 or newer for version 3, and it ships as an ES module with the type field set to module.

What does basic-auth parse return for an invalid header?

parse returns undefined when the string is not a valid Basic authorization header, so callers have to handle the failure case rather than assume an object. A valid header gives an object with name and pass properties.

Can I use basic-auth with an ESM project?

Version 3 is published as an ES module, since the manifest sets type to module and the exports map points at dist/index.js, even though the documented examples use require. Use an import statement in ESM code, or pin to the 2.x line if you need the CommonJS build the examples show.

Does basic-auth verify user passwords?

No, it only parses. The example server compares the parsed values against a check function backed by your user store, and it uses a separate timing-safe comparison module for that step, comparing both fields without short circuiting.

Is the basic-auth module size checked in CI?

Yes. A size-limit configuration in the package manifest sets a 1 kB limit on dist/index.js, and the test script runs the size check after the test suite, so a dependency that pushes the bundle past the limit fails the build.

Official sources

  1. Issues
  2. jshttp/basic-auth on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jshttp-basic-auth.svg)](https://hysenlabs.com/projects/jshttp-basic-auth)