# activitypub-http-signatures

> A library for creating, parsing, and verifying HTTP signature headers, as per the [Signing HTTP Messages draft 80](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-08) specification.

Latest version **2.5.0** (published 2024-05-13) · ISC license · 0 weekly downloads

## Install

```sh
npm install activitypub-http-signatures
pnpm add activitypub-http-signatures
yarn add activitypub-http-signatures
bun add activitypub-http-signatures
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.5.0 |
| Published | 2024-05-13 |
| First published | 2021-10-26 |
| Weekly downloads | 0 |
| License | ISC |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 33.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Paul Kiddle |
| Maintainers | paulkiddle |
| Keywords | activitypub, sign, request, fetch, signed, http, signature, draft |

## Links

- npm: https://www.npmjs.com/package/activitypub-http-signatures
- Repository: https://gitlab.com/paulkiddle/activitypub-http-signatures
- Homepage: https://gitlab.com/paulkiddle/activitypub-http-signatures#readme
- Issues: https://gitlab.com/paulkiddle/activitypub-http-signatures/issues
- npm.io page: https://npm.io/package/activitypub-http-signatures

## Alternatives

- [launchdarkly-js-client-sdk](https://npm.io/package/launchdarkly-js-client-sdk.md) — 2.5M weekly downloads
- [@elastic/elasticsearch](https://npm.io/package/@elastic/elasticsearch.md) — 2.1M weekly downloads
- [@c8y/client](https://npm.io/package/@c8y/client.md) — 15.3K weekly downloads
- [@signaldb/maverickjs](https://npm.io/package/@signaldb/maverickjs.md) — 1.7K weekly downloads
- [@bbc/http-transport-cache](https://npm.io/package/@bbc/http-transport-cache.md) — 1.2K weekly downloads

## Recent versions

- 2.5.0 (latest) — 2024-05-13
- 2.4.0 — 2024-02-23
- 2.3.1 — 2024-02-16
- 2.3.0 — 2024-02-16
- 2.2.0 — 2024-01-12
- 2.1.1 — 2024-01-03
- 2.1.0 — 2024-01-03
- 2.0.1 — 2022-03-14
- 2.0.0 — 2022-02-05
- 1.1.0 — 2021-11-28
- 1.0.0 — 2021-10-26

## README

# ActivityPub HTTP Signatures

A library for creating, parsing, and verifying HTTP signature headers, as per the [Signing HTTP Messages draft 08](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures-08) specification.

## Basic use

### Signing

#### Signed Fetch

The simplest way to make a signed request is using SignedFetch. In this method you create a
fetch-like function that automatically signs requests before sending them.

Note that this function only supports a subset of `fetch`'s options - for more advanced
usage or for use with other HTTP libraries, see the next section.

```javascript
import { Sha256Signer } from 'activitypub-http-signatures';
import fetch from 'node-fetch';

// You should make the public key available at this URL
const publicKeyId = 'http://my-site.example/@paul#main-key';
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
${process.env.PRIVATE_KEY}
-----END RSA PRIVATE KEY-----`;

export async function postResource(url, body) {
	// You need to bring your own fetch function and public/private key pair;
	// see the next section for more info
	const signedFetch = SignedFetch.sha256(fetch, { publicKeyId, privateKey });
	const res = await signedFetch(url, {
		// This is a subset of `fetch`'s options - it only supports method and body,
		// and the object-form of headers (i.e. not the Headers class instance).
		method: 'POST',
		headers: {
			'content-type': 'application/ld+json'
		},
		body
	});

	// The response object is whatever your base fetch function returns
	return res.ok;
}
```

#### Generating the signed headers

The following example illustrates using the lower-level library functions to sign requests:

```javascript
import { Sha256Signer } from 'activitypub-http-signatures';
import fetch from 'node-fetch';

// You should make the public key available at this URL
const publicKeyId = 'http://my-site.example/@paul#main-key';
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
${process.env.PRIVATE_KEY}
-----END RSA PRIVATE KEY-----`;

export function getResource(url) {
	// Create the instance of the signer class
	// You can pass an optional `headers` array to specify which headers should be
	// used in the signature.
	// The default is ['(request-target)', 'host', 'date']
	const signer = new Sha256Signer({ publicKeyId, privateKey });

	// A dict of the headers used in your request.
	// The host and date headers will be added automatically
	// if they're missing.
	const headers = {
		accept: 'application/ld+json'
	}
	const method = 'GET';

	// Generate the date, host and signature headers, and add to
	// the accept header dict.
	const signedHeaders = signer.generateHeaders({
		url,
		method,
		headers
	});

	// Create the HTTP request with the generated header
	// You could use fetch or any other HTTP library
	return fetch(
		url,
		{
			headers: signedHeaders,
			// (you can add any other options your fetch implementation supports)
		}
	)
}
```

### Verifying

```javascript
import parser from 'activitypub-http-signatures';
import fetch from 'node-fetch';

// Assuming we're dealing with a nodejs IncommingMessage
export async function verifyIncomingRequestSignature(req){
	// Parse the fields from the signature header
	// NB: If you're using express, you need to use originalUrl instead of url
	const { url, method, headers } = req;
	const signature = parser.parse({ url, method, headers });

	// If there's no signature header the parse function will return null
	if(signature === null) {
		throw new Error('The headers object has no `signature` key');
	}

	// Get the public key object using the provided key ID
	const keyRes = await fetch(
		signature.keyId,
		{
			headers: {
				accept: 'application/ld+json, application/json'
			}
		}
	);

	const { publicKey } = await keyRes.json();

	// Verify the signature
	const success = signature.verify(
		publicKey.publicKeyPem,	// The PEM string from the public key object
	);

	if(!success){
		throw new Error('http signature validation failed')
	} else {
		return publicKey.owner
	}
}
```

## Changes in V2

Version 2 of this package has a completely new and hopefully simpler API.
All previous exports have been removed,
you now need to use `Sha256Signer` to sign outgoing requests
and `Parser` to parse and verify incoming requests.
See the examples above for details.

Typescript definitions are included since V2.1.0

---
_Source: https://npm.io/package/activitypub-http-signatures · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
