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

activitypub-webfinger

v0.5.0

Published

WebFinger utilities for ActivityPub

Readme

activitypub-webfinger

WebFinger utilities for ActivityPub

Resolve WebFinger addresses to ActivityPub actor IDs and derive WebFinger addresses from actor documents. This package uses ECMAScript modules and supports an injected Fetch-compatible function.

For background on forward and reverse discovery, see the ActivityPub and WebFinger profile, published by the W3C Social Web Incubator Community Group on 8 June 2024.

Table of Contents

Security

This package does not perform server-side request forgery (SSRF) checks. Its default transport is global fetch, which can connect to private or internal network addresses, including through redirects.

When looking up user-supplied addresses or actor URLs, pass a Fetch-compatible function through options.fetch that enforces your network policy, including checks on resolved IP addresses and redirect destinations. Both discovery functions pass this fetch function to their verification lookups when verify is enabled. The verify option checks identity consistency; it does not provide SSRF protection.

For example, install the optional guarded-fetch package in your application:

npm install guarded-fetch

Then supply its Fetch-compatible function:

import { guardedFetch } from 'guarded-fetch'
import { actorIdOf, webfingerOf } from 'activitypub-webfinger'

const actorId = await actorIdOf('[email protected]', {
  fetch: guardedFetch,
  verify: true
})
const address = await webfingerOf('https://remote.example/user/river', {
  fetch: guardedFetch,
  verify: true
})

guarded-fetch checks destination IP addresses and redirects to help prevent SSRF. It is an optional application dependency, not a dependency of this package. Its bare guardedFetch function does not limit response-body size; consult its documentation when choosing resource limits for your application. Blocked or failed discovery requests result in null.

Install

Install from the repository:

npm install github:social-web-foundation/activitypub-webfinger

Use a Node.js version that provides global fetch.

Usage

import { actorIdOf, webfingerOf } from 'activitypub-webfinger'

const actorId = await actorIdOf('[email protected]')
const address = await webfingerOf('https://remote.example/user/river')

The example addresses are placeholders. Replace them with an existing account and actor URL. Both functions return null when lookup or processing fails.

See CHANGELOG.md for changes.

API

actorIdOf(webfinger, options = {})

An async function that returns an actor ID string, or null if none can be found.

  • webfinger: a WebFinger address, such as [email protected].
  • options.fetch: an optional Fetch-compatible function. Defaults to global fetch.
  • options.verify: an optional boolean, defaulting to false. When true, discovers the returned actor's WebFinger address and requires it to match the input address. A failed verification lookup or mismatch returns null.

Queries WebFinger and returns the href of the first matching self link with media type application/activity+json or application/ld+json; profile="https://www.w3.org/ns/activitystreams". It fetches the linked actor document only when verification is enabled.

The input address may contain a Unicode username, a Unicode domain, or both, such as élise@例え.example. For the WebFinger request, the username is percent-encoded and the domain is converted to its ASCII Punycode form. In this example, the resource is acct:%C3%[email protected]; this resource is then encoded as a query parameter. ASCII Punycode domains are also accepted. The returned actor ID is the link's href as supplied by the server; its domain and path are not converted or decoded.

webfingerOf(actorId, options = {})

An async function that returns a WebFinger address string, or null if none can be found.

  • actorId: an ActivityPub actor URL.
  • options.fetch: an optional Fetch-compatible function. Defaults to global fetch.
  • options.verify: an optional boolean, defaulting to false. When true, resolves the discovered WebFinger address and requires the resulting actor ID to match the input actor ID. A failed verification lookup or mismatch returns null.

Fetches the actor document and delegates address extraction to webfingerFromJson(). If the document contains https://purl.archive.org/socialweb/webfinger#webfinger, defined by FEP-2c59: Discovery of a Webfinger address from an ActivityPub actor, returns its first string value. An acct: URI is converted to a readable address by decoding the username and converting its Punycode domain to Unicode. For example, acct:%C3%[email protected] becomes élise@例え.example. This conversion occurs before verification. Otherwise, combines the first preferredUsername value with the hostname of the actor document's id, producing an address such as [email protected]. The fallback requires an HTTPS actor ID.

The actor URL may use a Unicode or ASCII Punycode domain. In the preferredUsername fallback, the username is preserved as supplied by the actor document and the URL's Punycode hostname is converted to Unicode. For example, an actor URL on xn--r8jz45g.example with preferredUsername set to élise produces élise@例え.example.

An explicit webfinger value without an acct: prefix is returned unchanged. Explicit metadata takes precedence over the fallback.

The fallback is inferred from the actor document and may differ from the account address when the account and actor use different domains. Set verify: true to check that it resolves back to the original actor.

The profile describes verifying that an inferred address resolves back to the same actor. Enable this with webfingerOf(actorId, { verify: true }).

Both functions use the supplied fetch for the initial and verification lookups. The reverse lookup runs without verification to avoid recursion. When verify is false or omitted, only the initial lookup is performed, regardless of whether a reverse lookup would match. Verification uses exact string comparisons; it does not normalize addresses or actor IDs.

For forward discovery, check whether the discovered actor's reported or inferred WebFinger address matches the address you started with. Use actorIdOf(address, { verify: true }).

Aliases, an acct: prefix, or hostname capitalization can cause a mismatch even when the original address resolves to the intended actor. Unicode and Punycode forms of the same domain, percent-encoded and unencoded usernames, or different Unicode normalization forms can also cause a mismatch. For example, forward verification of é[email protected] fails if the reverse lookup returns élise@例え.example.

webfingerFromJson(json)

A synchronous function that returns a readable WebFinger address string from an actor's JSON profile. It performs no network requests or JSON-LD expansion and does not return a Promise.

  • json: the actor document as a parsed JavaScript object.

Recognizes these field names in precedence order:

| Value | Field names, highest precedence first | | --- | --- | | WebFinger address | webfinger, wf:webfinger, https://purl.archive.org/socialweb/webfinger#webfinger | | Username | preferredUsername, as:preferredUsername, https://www.w3.org/ns/activitystreams#preferredUsername | | Actor ID | id, @id |

For each value, the first present field is selected; an invalid value does not cause later spellings to be tried. Fields must contain strings, rather than JSON-LD arrays or value objects. Context definitions and custom aliases are not interpreted.

A string WebFinger address takes precedence over username-based derivation. If it starts with acct:, the username is percent-decoded and the domain is converted from Punycode to Unicode; otherwise the value is returned unchanged. When the selected WebFinger field is absent or is not a string, derives the address from the selected username and actor ID using webfingerFromUsername().

Throws synchronously for invalid input or insufficient properties to derive an address. Address conversion and fallback validation errors also propagate. Unlike webfingerOf(), this helper does not convert errors to null or verify the resulting address.

webfingerFromUsername(preferredUsername, id)

A synchronous function that returns a readable username@domain address without performing network requests.

  • preferredUsername: a nonempty, unencoded username string, preserved as supplied.
  • id: an absolute HTTPS actor ID string. Its hostname is converted from Punycode to Unicode; its port, path, query, and fragment are excluded.

The returned address has no acct: prefix. Throws a TypeError for empty or non-string arguments, or an error for a malformed URL or a scheme other than HTTPS. This helper infers an address; it does not validate the username against PRECIS or verify that the address resolves to the actor.

Maintainers

Evan Prodromou

Contributing

Use GitHub Issues for questions, bug reports, and proposed changes. Please discuss substantial changes with the maintainer before submitting a pull request.

Install dependencies, check StandardJS style, and run the tests from a local checkout:

npm install
npm run lint
npm test

Tests use Node's built-in test runner and @evanp/activitypub-nock.

Run the browser suite in headless Chromium:

npx playwright install chromium
npm run test:browser

The suite bundles the library and its dependencies with esbuild for the browser, then tests both lookup directions, verification matches and mismatches, custom fetch, HTTP failures, and username fallback. Playwright intercepts requests; the tests do not contact external services. Browser installation requires network access. CI requires both Node.js and Chromium tests before publishing.

License

Licensed under the Apache License, Version 2.0.