Vibefed kb-fediverse-webfinger-discovery
git clone https://github.com/reiver/vibefed
T=$(mktemp -d) && git clone --depth=1 https://github.com/reiver/vibefed "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/kb-fediverse-webfinger-discovery" ~/.claude/skills/reiver-vibefed-kb-fediverse-webfinger-discovery && rm -rf "$T"
skills/kb-fediverse-webfinger-discovery/SKILL.mdReverse WebFinger Discovery (FEP-2c59) — Complete Reference
Overview
WebFinger (RFC 7033) is the standard mechanism for discovering an ActivityPub actor from a human-friendly address like
user@domain.example.
The forward direction (WebFinger to actor) is well-defined. The
reverse direction (actor to WebFinger address) is not — and this causes
real problems across the Fediverse.
FEP-2c59 (authored by Evan Prodromou, received 2024-01-04, status DRAFT) proposes adding a
webfinger property to ActivityPub actor objects to solve
the reverse discovery problem explicitly.
The Problem: Reverse Discovery Is Broken
Forward Discovery (Well-Defined)
Converting
user@domain to an actor URL is straightforward:
- Construct the query:
https://domain/.well-known/webfinger?resource=acct:user@domain - Parse the JRD (JSON Resource Descriptor) response
- Extract the
from the link withhref
and an ActivityPub media typerel="self"
Reverse Discovery (Problematic)
Going the other direction — from an actor URL back to a
user@domain
handle — has no standard mechanism. Current implementations reconstruct it
by extracting preferredUsername from the actor and combining it with the
hostname from the actor's id URL:
actor.preferredUsername + "@" + hostname(actor.id)
This approach has three fundamental problems:
-
is optional — it is not a required property in the ActivityPub specification, so it may be absent entirely.preferredUsername -
Domain mismatch — organizations may want WebFinger addresses on a different domain than where their ActivityPub server runs. For example,
while the AP server is atalice@company.tld
. The current approach constructssocial.company.tld
instead.alice@social.company.tld -
Semantic overload —
serves double duty as both a display name preference and the WebFinger handle component, preventing it from serving either purpose cleanly.preferredUsername
The W3C Social Web Incubator Community Group (SWICG) acknowledged this explicitly in their "ActivityPub and WebFinger" report:
"Back-linking an actor to a WebFinger address could be more explicit. Current use of
is not ideal for constructing WebFinger addresses, and it also does not allow for expressing actual 'preferred usernames'."preferredUsername
The Solution: The webfinger
Property
webfingerFEP-2c59 proposes that actors SHOULD include a
webfinger property
containing their canonical WebFinger address.
Wire Format
The address may be plain or use the
acct: prefix:
{ "@context": [ "https://www.w3.org/ns/activitystreams", "https://purl.archive.org/socialweb/webfinger" ], "type": "Person", "id": "https://social.example/users/alice", "preferredUsername": "alice", "webfinger": "alice@example.org" }
Or with the
acct: prefix:
{ "webfinger": "acct:alice@example.org" }
Both forms are valid. The property is functional — at most one value per actor.
JSON-LD Context
The
webfinger property is registered under:
https://purl.archive.org/socialweb/webfinger
Include this URL in the actor's
@context array for proper JSON-LD
processing.
Domain Mismatch Use Case
The motivating scenario for FEP-2c59:
An organization hosts its ActivityPub server at
social.company.tld but
wants employees to have addresses like alice@company.tld. Today this works
via WebFinger redirects — company.tld/.well-known/webfinger redirects
queries to social.company.tld/.well-known/webfinger.
But Mastodon's reverse discovery constructs
alice@social.company.tld (from
the actor URL hostname), not alice@company.tld (the intended address).
With FEP-2c59:
{ "type": "Person", "id": "https://social.company.tld/users/alice", "preferredUsername": "alice", "webfinger": "alice@company.tld" }
The intended address is stated explicitly — no guessing required.
Validation Requirements
When an implementation encounters a
webfinger property, it MUST validate
the claim:
- Perform a WebFinger lookup on the stated address
- The JRD response MUST contain a
link whoseself
matches the actor'shref
URL exactlyid - No redirects allowed — the match must be a direct string comparison
Why No Redirects
RFC 7033 (WebFinger) makes HTTP redirects mandatory to support. FEP-2c59 deliberately prohibits redirects during validation to simplify confirmation to a string comparison. This was a point of contention in the community discussion, with mro arguing it violates RFC 7033 semantics. Evan Prodromou maintained that forbidding redirects makes validation unambiguous.
Validation Example
Given an actor with
"webfinger": "alice@company.tld" and
"id": "https://social.company.tld/users/alice":
- Query
https://company.tld/.well-known/webfinger?resource=acct:alice@company.tld - Expect a JRD with a link:
{ "subject": "acct:alice@company.tld", "links": [ { "rel": "self", "type": "application/activity+json", "href": "https://social.company.tld/users/alice" } ] } - Confirm
equals the actor'shref
— validation passesid
Security Considerations
The
webfinger property should only be trusted when:
- It comes from dereferencing the actor's
URL directly (i.e., you fetched the actor document from its authoritative origin)id - It is delivered with the actor's HTTP Signature via ActivityPub
A third party could spoof the
webfinger property otherwise. For example,
if actor A delivers an activity containing actor B's profile with a modified
webfinger value, the recipient should not trust that claim without
independent verification.
Always validate the
webfinger claim by performing the forward WebFinger
lookup and confirming the self link matches.
Mastodon's Current Reverse Discovery
Mastodon does not implement FEP-2c59. It uses the
preferredUsername +
hostname approach:
- Extract
and the hostname from the actor'spreferredUsername
URLid - Construct
acct:preferredUsername@hostname - Perform a WebFinger lookup to verify the address resolves back to the same actor
- If the JRD
differs from the requested resource, follow up with another WebFinger request to the canonical subjectsubject
Mastodon Username Rules
- Alphanumeric characters and underscores allowed anywhere
- Dots and dashes only in the middle (not at start or end)
- Case-insensitive
- Regex:
[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?
When Mastodon's Approach Breaks
is absent from the actorpreferredUsername- The WebFinger domain differs from the actor URL domain
- The actor URL uses subdomains or non-standard paths
contains characters not valid in WebFinger handlespreferredUsername
Community Debate: Alternative Approaches
The SocialHub discussion revealed several alternative proposals:
alsoKnownAs
(stevebate)
alsoKnownAsUse the existing
alsoKnownAs property with acct: URIs instead of adding
a new property. Evan Prodromou objected because Mastodon uses alsoKnownAs
for its Move (account migration) function — adding WebFinger addresses to
it could interfere with migration semantics.
aliases
from XRD/JRD (erincandescent)
aliasesUse the
aliases array concept from WebFinger's JRD format:
{ "aliases": ["acct:bob@example.com"] }
Advantages cited:
- Aligns WebFinger XRD/JRD values directly with ActivityStreams
- Semantics are already understood because everyone implements WebFinger
- Enables future extensibility for emerging identifier schemes (e.g., DIDs)
- More capable than a dedicated
fieldwebfinger
Property Naming (trwnh)
Suggested renaming
webfinger to webfingerAcct or acct for semantic
clarity, since the property specifically holds an acct: URI, not a generic
WebFinger resource.
Related Specifications
| Specification | Relationship |
|---|---|
| RFC 7033 (WebFinger) | The underlying protocol; defines the endpoint and JRD format |
RFC 7565 ( URI) | Defines the URI scheme used in WebFinger queries |
| FEP-d556 | Complementary proposal for server-level actor discovery via WebFinger (vs FEP-2c59's user-level focus) |
| W3C SWICG "ActivityPub and WebFinger" report | Acknowledges the reverse discovery problem; does not reference FEP-2c59 by name |
Implementation Guidance
If You Are Building a New ActivityPub Server
- Include the
property on all actor objectswebfinger - Add
to thehttps://purl.archive.org/socialweb/webfinger@context - Set the value to the canonical
address (with or withoutuser@domain
prefix)acct: - Ensure your WebFinger endpoint returns a JRD with a
link pointing to the actor'sself
URLid
If You Are Consuming ActivityPub Actors
- Check for the
property firstwebfinger - If present, validate it by performing a forward WebFinger lookup and
confirming the
link matches the actor'sselfid - If absent, fall back to the
+ hostname approachpreferredUsername - Always verify any constructed address via forward WebFinger lookup
Defensive Parsing
- Accept both
and"user@domain"
formats"acct:user@domain" - Strip the
prefix before display (users expectacct:
)user@domain - Do not assume
exists — it is optionalpreferredUsername - Do not assume the WebFinger domain matches the actor URL domain
Known Issues and Open Questions
- DRAFT status — FEP-2c59 has not reached FINAL status; no implementations are listed in the FEP itself
- No-redirect controversy — the prohibition on redirects during validation conflicts with RFC 7033's mandatory redirect support
- Property naming unresolved — whether
,webfinger
, orwebfingerAcct
is the best name remains debatedacct
alternative — the community has not reached consensus on whether a dedicated property or thealiases
approach is preferablealiases- Mastodon adoption unknown — Mastodon has not indicated plans to adopt FEP-2c59
- JSON-LD context availability — the
context document's long-term availability is not guaranteedhttps://purl.archive.org/socialweb/webfinger
WebFinger Protocol Quick Reference
For implementors who need a refresher on the underlying WebFinger protocol:
- Endpoint:
GET /.well-known/webfinger?resource=acct:user@domain - Response: JRD (JSON Resource Descriptor) with
, optionalsubject
, andaliases
arraylinks - Key link relation:
withrel="self"
(ortype="application/activity+json"
) points to the ActivityPub actor URLapplication/ld+json; profile="https://www.w3.org/ns/activitystreams" - Standard: RFC 7033 (IETF, 2013)
- Not part of ActivityPub — WebFinger is a convention the Fediverse adopted; the W3C ActivityPub spec does not mention it