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

fetch-message-signatures

v0.1.0

Published

HTTP Message Signatures (RFC 9421) for the Fetch API

Readme

fetch-message-signatures

fetch-message-signatures is a JavaScript module for HTTP Message Signatures (RFC 9421) built on the Fetch API.

The module provides sender, recipient, and Accept-Signature operations on top of Request, Response, Headers, and fetch, together with Web Cryptography implementations for ECDSA P-256, ECDSA P-384, Ed25519, RSA-PSS with SHA-512, and RSASSA-PKCS1-v1_5 with SHA-256. HMAC and other cryptography can be supplied through custom providers. Trusted-key selection and authorization remain application responsibilities.

RFC 9421 is built on Structured Fields (RFC 9651), and the parser and serializer behind it are exported for HTTP fields this module does not define.

💗 Help the project

Support from the community to continue maintaining and improving this module is welcome. If you find this module useful, please consider supporting this project by becoming a sponsor.

Dependencies: 0

fetch-message-signatures has no dependencies and it exports tree-shakeable ESM from a single module.

API Reference

fetch-message-signatures is distributed via npmjs.com, jsdelivr.com, and github.com.

Quick Start

Sign every outgoing request and send it. createSigningFetch() returns a drop-in fetch, so the signing happens around the call you already make.

import * as FetchSig from 'fetch-message-signatures'

// 1. Your signing key
const { privateKey } = await FetchSig.generateEd25519KeyPair()

// 2. Wrap fetch
const signingFetch = FetchSig.createSigningFetch({
  sign: {
    signer: FetchSig.ed25519Signer(privateKey),
    components: ['@method', '@authority', '@path'],
    parameters: { alg: 'ed25519', keyid: 'client-key' },
  },
})

// 3. Send it, exactly like fetch. The request goes out signed.
const response = await signingFetch('https://api.example/orders/123')
const order = await response.json()

The request that went out carries the two fields RFC 9421 defines:

signature-input: sig1=("@method" "@authority" "@path");created=1735689600;alg="ed25519";keyid="client-key"
signature:       sig1=:<base64 of the 64 Ed25519 signature bytes>:

The recipient checks that signature against explicit policy. A valid signature on its own is not enough: the components it covers and the parameters it carries have to be the ones the application requires, which is why the policy is spelled out rather than defaulted.

declare const incoming: Request
declare const clientPublicKey: CryptoKey

const verified = await FetchSig.verify(incoming, {
  verifier: FetchSig.ed25519Verifier(clientPublicKey),
  policy: {
    requiredComponents: ['@method', '@authority', '@path'],
    requiredParameters: ['created', 'keyid'],
    algorithms: ['ed25519'],
    maxAge: 60,
  },
})

// sig1 ed25519
console.log(verified.label, verified.algorithm)

A recipient that accepts more than one client selects the trusted key itself, from the signature's keyid. That is what VerifierFactory is for, and the recipient guide covers it.

Signing requests is the common direction, because it only asks the recipient to verify. When the server signs its responses too, createSignedFetch() adds verification on the way back in, and createVerifyingFetch() does that alone so a bundler can omit the signing side. To sign a message you already hold, rather than wrapping fetch, use sign().

The bytes that were signed are one canonicalized line per covered component plus the @signature-params line, which repeats the Signature-Input member value. createSignatureBase() returns exactly that string, which is the first thing to compare when two implementations disagree:

"@method": GET
"@authority": api.example
"@path": /orders/123
"@signature-params": ("@method" "@authority" "@path");created=1735689600;alg="ed25519";keyid="client-key"

Guides

For sender and recipient integration, cryptographic providers, component selection, Structured Fields, Accept-Signature, Fetch behavior, and security guidance, see the guides directory.

Runtime Requirements

The Fetch wrappers, sign(), appendSignature(), signRequested(), and appendAcceptSignature() require standards-compatible Request, Response, and Headers implementations, and the wrappers also require fetch itself. Every reading operation, including createSignature() and verify(), additionally accepts a plain object carrying method, url, and headers for a request, or status and headers for a response, so a server that never constructs a Request can sign and verify by attaching the returned field values itself. A descriptor field value can be an array of occurrences in wire order, and an optional trailers record supplies trailer occurrences. The built-in cryptographic providers require the Web Cryptography API and runtime support for the selected algorithm. The package does not provide polyfills.

Signing and verification capture the target message and related request into package-owned, immutable snapshots. A verifier factory and policy.validate receive the same MessageSnapshot, whose lowercase header and trailer names map to frozen occurrence arrays, rather than the caller's mutable message object. Keep the source message stable until the operation settles: it is compared with the snapshot after application callbacks run, and a change rejects the operation.

Package configuration records must be object literals or null-prototype objects whose own members are enumerable data properties. Frozen records are supported; class instances, inherited or non-enumerable configuration, accessors, and Proxies are not. Fetch-wrapper RequestInit values follow the same rule. This restriction does not apply to message and header inputs, cryptographic provider implementations, or host objects such as CryptoKey, Request, Response, and Headers.

Structured Field Byte Sequences use Uint8Array.prototype.toBase64() and Uint8Array.fromBase64() where they are available, and fall back to btoa() and atob() where they are not. Both paths produce the same results and are covered by the test suite.

Runtime-specific behavior that affects signatures, such as manual redirect handling in browsers, repeated field lines, trailers, and response reconstruction, is documented in Fetch behavior and limitations.

Supported Operations

  • Sign requests and responses.
  • Verify one or more message signatures against explicit recipient policy.
  • Generate key pairs containing Web Cryptography's CryptoKey objects and providers for ECDSA P-256, ECDSA P-384, Ed25519, RSA-PSS with SHA-512, and RSASSA-PKCS1-v1_5 with SHA-256.
  • Bind a response signature to components of its related request.
  • Create, parse, append, and fulfill Accept-Signature requests.
  • Derive RFC 9421 request and response components from Fetch messages or plain descriptors.
  • Process HTTP fields as Structured Fields, dictionary members, raw byte sequences, or trailers.
  • Parse and serialize Structured Field Dictionaries, Lists, and Items.
  • Wrap fetch with request signing, response verification, or both through independent tree-shakeable exports.

Cryptographic Algorithms

fetch-message-signatures includes tree-shakeable key-pair generators, signer factories, and verifier factories backed by Web Cryptography for ecdsa-p256-sha256, ecdsa-p384-sha384, ed25519, rsa-pss-sha512, and rsa-v1_5-sha256. Other algorithm identifiers and key systems, including hmac-sha256, can be supplied through the Signer and Verifier interfaces. Applications choose trusted keys, algorithms, and authorization policy.

The cryptographic providers guide documents the exact algorithm mappings, key extractability, signature parameter handling, and custom provider contract. Exported functions are listed under Cryptographic Algorithms in the API reference.

Security Considerations

A valid signature authenticates only its covered components. It does not by itself establish authorization, freshness, replay protection, or body integrity. Applications must define trusted keys, required component coverage, timestamp and nonce policy, and independently validate Content-Digest when body integrity matters.

Fetch also hides or normalizes some protocol-layer HTTP details. Read the security guidance and Fetch behavior before deploying signatures across a network boundary. Security vulnerabilities should be reported according to the Security Policy.

Specifications