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

@gyeonghokim/ky-digest-auth

v0.1.0

Published

HTTP Digest Authentication for Ky. Built for CCTV, NVR, and other embedded devices.

Downloads

28

Readme

@gyeonghokim/ky-digest-auth

npm version CI license

HTTP Digest Authentication for Ky.

Install

npm install ky @gyeonghokim/ky-digest-auth

Usage

import ky from 'ky';
import {digestAuth} from '@gyeonghokim/ky-digest-auth';

const api = ky.create({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

const data = await api
  .get('https://device.example.com/api/status')
  .json();

console.log(data);

The plugin automatically:

  1. Receives the 401 Unauthorized response.
  2. Parses the WWW-Authenticate: Digest challenge.
  3. Calculates the Digest authorization response.
  4. Retries the request with the generated Authorization header.

API

digestAuth(options)

Returns a Ky hooks configuration that handles HTTP Digest Authentication.

import ky from 'ky';
import {digestAuth} from '@gyeonghokim/ky-digest-auth';

const api = ky.create({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

Options

username

Type: string

The username used for Digest Authentication.

password

Type: string

The password used for Digest Authentication.

algorithms

Type:

Array<
  | 'MD5'
  | 'MD5-sess'
  | 'SHA-256'
  | 'SHA-256-sess'
  | 'SHA-512-256'
  | 'SHA-512-256-sess'
>

Optional list of allowed Digest algorithms.

const api = ky.create({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
    algorithms: ['SHA-256', 'MD5'],
  }),
});

When omitted, all algorithms supported by this package are allowed.

Many embedded devices (CCTV, NVR, and similar systems) still issue MD5 challenges. Because the Web Crypto API does not implement MD5 or SHA-512-256, this package computes every Digest hash with @noble/hashes, an audited, zero-dependency, tree-shakeable hashing library. All listed algorithms work in any supported runtime without extra configuration. See Supported environments for details.

preemptive

Type: boolean Default: false

Reuses a previously received Digest challenge for later requests to the same protection space.

const api = ky.create({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
    preemptive: true,
  }),
});

The first request still requires a server challenge.

cnonce

Type: () => string

Overrides the client nonce generator.

const api = ky.create({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
    cnonce: () => 'custom-client-nonce',
  }),
});

This is mainly useful for deterministic tests. The default implementation uses a cryptographically secure random value.

Examples

Typed JSON response

import ky from 'ky';
import {digestAuth} from '@gyeonghokim/ky-digest-auth';

type DeviceStatus = {
  online: boolean;
  firmwareVersion: string;
};

const api = ky.create({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

const status = await api
  .get('https://device.example.com/api/status')
  .json<DeviceStatus>();

console.log(status.firmwareVersion);

Create a reusable client

const deviceApi = ky.create({
  baseUrl: 'https://device.example.com/api/',
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

const status = await deviceApi.get('status').json();
const configuration = await deviceApi.get('configuration').json();

Send JSON

await deviceApi.put('configuration', {
  json: {
    enabled: true,
    quality: 'high',
  },
});

Extend an existing Ky instance

const baseApi = ky.create({
  timeout: 10_000,
  headers: {
    Accept: 'application/json',
  },
});

const deviceApi = baseApi.extend({
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

Combine with other hooks

Ky hook arrays must be merged when multiple integrations use the same lifecycle hook.

const digestHooks = digestAuth({
  username: 'admin',
  password: 'password',
});

const api = ky.create({
  hooks: {
    beforeRequest: [
      ({request}) => {
        request.headers.set('X-Client-Version', '1.0.0');
      },
    ],
    afterResponse: [
      ({response}) => {
        console.log(response.status);
      },
      ...(digestHooks.afterResponse ?? []),
    ],
  },
});

Retry behavior

Digest Authentication requires at least one additional request after receiving the initial challenge.

The plugin uses Ky's afterResponse hook and forced retry mechanism to retry the request with the generated Authorization header.

Do not disable retries completely:

const api = ky.create({
  retry: {
    limit: 1,
  },
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

The following configuration prevents Digest Authentication from completing:

const api = ky.create({
  retry: {
    limit: 0,
  },
  hooks: digestAuth({
    username: 'admin',
    password: 'password',
  }),
});

The plugin prevents an authentication challenge from causing an infinite retry loop.

CORS

HTTP Digest Authentication does not bypass the browser's same-origin policy.

For a cross-origin request, the server must expose the WWW-Authenticate response header:

Access-Control-Expose-Headers: WWW-Authenticate

It must also allow the Authorization request header:

Access-Control-Allow-Headers: Authorization, Content-Type

A typical CORS response may include:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Expose-Headers: WWW-Authenticate

Many embedded devices do not provide a complete CORS implementation. When the target server does not support the required CORS headers, use a same-origin backend or reverse proxy.

Browser
   |
   | Application authentication
   v
Backend or reverse proxy
   |
   | Digest Authentication
   v
Device or legacy service

Security

Do not embed shared service credentials in publicly distributed browser code.

Credentials used by browser JavaScript can be inspected by the current user. Browser-side Digest Authentication is appropriate when:

  • the user provides their own credentials;
  • the user is permitted to access those credentials; or
  • the application runs in a controlled environment with an appropriate threat model.

Use a trusted backend for fixed or privileged service credentials.

Digest Authentication does not encrypt HTTP traffic. Use HTTPS whenever the target server supports it.

Supported environments

The package requires a Fetch-compatible runtime with:

  • fetch
  • Request
  • Response
  • Headers
  • crypto.getRandomValues (for the default client nonce)

It is intended for modern browsers and other runtimes supported by Ky.

Hashing

The Web Crypto API only exposes SHA-1, SHA-256, SHA-384, and SHA-512. It does not provide MD5 or SHA-512-256, both of which are common in the Digest challenges issued by CCTV, NVR, and other embedded devices. (SHA-512-256 is a distinct algorithm from SHA-512, using different initial values rather than a simple truncation, so a native SHA-512 digest cannot be reused for it.)

Rather than relying on Web Crypto for hashing, the package computes every algorithm through @noble/hashes:

| Algorithm | Module | | -------------------------------- | -------------------------- | | MD5, MD5-sess | @noble/hashes/legacy.js | | SHA-256, SHA-256-sess | @noble/hashes/sha2.js | | SHA-512-256, SHA-512-256-sess| @noble/hashes/sha2.js |

@noble/hashes is an audited, zero-dependency, tree-shakeable library, so only the algorithms you actually use are included in your bundle, and every listed algorithm works in any Fetch-compatible runtime out of the box. It is installed automatically as a dependency of this package.

Supported authentication

This package handles HTTP Digest Authentication.

It does not provide:

  • Basic Authentication
  • Bearer tokens
  • OAuth
  • NTLM
  • Negotiate or Kerberos
  • form-based authentication
  • cookie-based session management

License

MIT