Identifiers in ActivityPub tend to be HTTPS URIs. The use of WebFinger (as defined in [[RFC7033]]) allows for discovery of an actor's identifier given a username and a hostname, which may be more socially salient or otherwise easier to communicate across various contexts and media. The username and hostname are resolved at the WebFinger endpoint of the hostname in order to discover a link to an actor associated with the user's account, and that actor similarly can be back-linked to the username and hostname.
Consider an HTTPS URI of the form https://social.example/actors/9c5b94b1-35ad-49bb-b118-8e8fc24abf80
being used as an identifier for an actor associated with a user account. Communicating this digitally may be done by simply using the HTTPS URI as-is, as a hyperlink reference. However, communicating this verbally or in a space-constrained visual format can be difficult. WebFinger allows communicating aliases of the form alyssa@social.example
, which are easier to work with in the previously-cited cases.
Additional benefits of using WebFinger include smoothing over the differences between varying actor URI schemas. Different softwares may provide human-friendly URLs for an actor's profile, but these URLs may take several different forms:
https://social.example/alyssa
https://social.example/@alyssa
https://social.example/~alyssa
https://social.example/u/alyssa
Conventionally, people can be identified by their user@domain address, while documents can be identified by their HTTPS location.
Discovery can occur in one of two directions:
The former will be referred to as "forward discovery" and the latter will be referred to as "reverse discovery".
Given a username and hostname in the form user@domain
:
acct:
URI of the form acct:user@domain
(as defined in [[RFC7565]])acct:
URI as the value of the resource
query parameter (as described in [[RFC7033]])For example, the WebFinger address alyssa@social.example
can be resolved as a resource by making an HTTP GET request for https://social.example/.well-known/webfinger?resource=acct:alyssa@social.example
(which is https://social.example/.well-known/webfinger?resource=acct:alyssa%40social.example
when percent-encoded). This request MAY result in an HTTP 3xx redirect, in which case the redirect MUST be followed to the Location
header's value, which MUST be an https:
URI per [[RFC7033]]. (Subsequent redirects SHOULD be followed, up until a maximum redirect limit at the discretion of the requester.) The final request MUST return a JRD (JSON Resource Descriptor, as defined in [[RFC6415]]) with application/jrd+json
as the content type (assuming no specified Accept
header).
The WebFinger request and response may look like this:
GET /.well-known/webfinger?resource=acct:alyssa%40social.example HTTP/1.1 Host: social.example HTTP/1.1 307 Temporary Redirect Location: https://social.example/jrd/alyssa GET /jrd/alyssa HTTP/1.1 Host: social.example HTTP/1.1 200 OK Content-Type: application/jrd+json { "subject": "acct:alyssa@social.example", "aliases": [ "https://social.example/@alyssa", "https://social.example/actors/9c5b94b1-35ad-49bb-b118-8e8fc24abf80" ], "links": [ { "rel": "http://webfinger.net/rel/profile-page", "type": "text/html", "href": "https://social.example/@alyssa" }, { "rel": "self", "type": "application/activity+json", "href": "https://social.example/actors/9c5b94b1-35ad-49bb-b118-8e8fc24abf80" } ] }
At this point, you can parse for the href
of the element of links
that has a rel
of self
and a type
of either application/ld+json; profile="https://www.w3.org/ns/activitystreams"
or application/activity+json
(depending on the implementation). See for more information about this.
Given an actor with an id
and a preferredUsername
:
id
to discover the WebFinger domainpreferredUsername
and the WebFinger domain in order to form a WebFinger addresssubject
and it contains an acct:
URI different from the one you constructed, perform a verification discovery against that acct:
URI afterward. (In such cases, the subject
of the JRD denotes the expected canonical identifier.)For example, given an actor document at https://activitypub.example.com/actor/1
like so:
{ "@context": "https://www.w3.org/ns/activitystreams", "id": "https://activitypub.example.com/actor/1", "preferredUsername": "alice", "name": "Alice P. Hacker" }
The reverse discovery process would extract alice
and activitypub.example.com
, construct the acct:
URI acct:alice@activitypub.example.com
, then request https://activitypub.example.com/.well-known/webfinger?resource=acct:alice@activitypub.example.com
like so:
GET /.well-known/webfinger?resource=acct:alice@activitypub.example.com HTTP/1.1 Host: activitypub.example.com HTTP/1.1 200 OK Content-Type: application/jrd+json { "subject": "acct:alice@example.com", "aliases": [ "https://example.com/@alice", "https://activitypub.example.com/actors/1" ], "links": [ { "rel": "http://webfinger.net/rel/profile-page", "type": "text/html", "href": "https://example.com/@alice" }, { "rel": "self", "type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "href": "https://activitypub.example.com/actors/1" } ] }
At this point, we have validated that alice@activitypub.example.com
links back to our actor document, but we can optionally verify that the canonical WebFinger address of alice@example.com
also links back to the same actor document:
GET /.well-known/webfinger?resource=acct:alice@example.com HTTP/1.1 Host: example.com HTTP/1.1 307 Temporary Redirect Location: https://activitypub.example.com/.well-known/webfinger?resource=acct:alice@example.com GET /.well-known/webfinger?resource=acct:alice@example.com HTTP/1.1 Host: activitypub.example.com HTTP/1.1 200 OK Content-Type: application/jrd+json { "subject": "acct:alice@example.com", "aliases": [ "https://example.com/@alice", "https://activitypub.example.com/actors/1" ], "links": [ { "rel": "http://webfinger.net/rel/profile-page", "type": "text/html", "href": "https://example.com/@alice" }, { "rel": "self", "type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "href": "https://activitypub.example.com/actors/1" } ] }
To ensure smooth operation of the WebFinger discovery flows, identifiers and responses should follow certain guidelines for encoding.
The acct:
URI scheme is defined in [[RFC7565]], which contains ABNF ([[RFC5234]]) for allowed characters (inheriting from [[RFC3986]] as well):
acctURI = "acct" ":" userpart "@" host userpart = unreserved / sub-delims 0*( unreserved / pct-encoded / sub-delims ) ; userpart regex: [A-Za-z0-9\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=](?:[A-Za-z0-9\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=]|(?:%[0-9A-Fa-f]{2}))* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" pct-encoded = "%" HEXDIG HEXDIG host = IP-literal / IPv4address / reg-name reg-name = *( unreserved / pct-encoded / sub-delims ) ; reg-name regex: (?:[A-Za-z0-9\-\.\_\~\!\$\&\'\(\)\*\+\,\;\=]|(?:%[0-9A-Fa-f]{2}))*
Further restrictions are specified in [[RFC7565]]:
unreserved
characters SHOULD be decoded if encountered as a percent-encoded octet.IdentifierClass
Note that while there are several symbols allowed in the userpart, the de facto limits set by some current implementers are much more restrictive.
At the time of this writing, Mastodon enforces the following rules:
A
through Z
, a
through z
, 0
through 9
) and underscores (_
) are generally allowed anywhere in the username.
) and dashes (-
) are allowed in the middle of a username, but not as the first character or the last characterIn other words, Mastodon will accept the regular expression or the following ABNF:
; As a regular expression, this can be expressed as follows: ; /[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?/i username = word *( rest ) word = ALPHA / DIGIT / "_" rest = *( extended ) word extended = word / "." / "-"
Similarly at the time of this writing, Misskey is subject to the following limitations:
id
in any references to an actor. (Implementers that currently treat usernames as canonical identifiers SHOULD take steps to avoid doing so in the future.)A-Z, a-z, 0-9
) and underscores (_
).As discussed in , the link to the actor associated with a given WebFinger address will have the following qualifiers:
rel
MUST be self
type
MUST be either application/activity+json
or application/ld+json; profile="https://www.w3.org/ns/activitystreams"
Publishers SHOULD include only one such link.
Due to the prevailing use of WebFinger addresses as canonical primary identifiers for users, implementations that require WebFinger for compatibility will often also deduplicate actors based on the WebFinger address. Therefore, it is generally expected that there is only one self
link to an Activity Streams document, in a unary relationship. However, some implementations do not follow this expectation, and there might be multiple links to ActivityStreams documents for the same WebFinger acct:
resource. In such cases, one of the following strategies may be employed:
Aside from the self-link to the associated actor, resolving a WebFinger query may expose some other links of potential interest. The following link relations are currently common among WebFinger implementers, and are recommended for use especially when the actor document is not publicly available:
http://webfinger.net/rel/profile-page
(for quickly getting the HTML profile page of a user without resolving their actor document and checking for the url
)http://webfinger.net/rel/avatar
(for quickly getting the avatar of a user without resolving their actor document and checking for the icon
)The following link relations are less common, but offer useful information to ActivityPub implementers:
http://ostatus.org/schema/1.0/subscribe
(used to power features like Mastodon's remote follow buttons)http://schemas.google.com/g/2010#updates-from
(used by some implementations to link to an Atom feed)feed
(used by some implementations to link to one or more feeds; feeds can be disambiguated by checking type
and/or title
properties of the link)http://a9.com/-/spec/opensearch/1.1/
(for custom search bars)Also uncommon but supported by at least one implementation (WordPress) is the ability to query non-actor, non-user resources via WebFinger. The following link relations are exposed:
shortlink
author
alternate
license
canonical
webmention
Using WebFinger can provide proof of existence of an associated actor document, as well as make it easier to discover that associated actor document; following this, an actor's inbox can be likewise discovered, and spam or other unwanted messages can be delivered to that actor's inbox. It may be desirable for some systems to not publicly expose an actor's existence and instead rely on the user manually entering their actor's HTTPS URI, or maintaining a "contact list" of bookmarked actors or resources. For such systems, the use of WebFinger is not advisable.
WebFinger allows for the lookup request to redirect; this primarily allows a web host or origin to defer or delegate their WebFinger lookups to a separate WebFinger service, but it can also create an issue when there are multiple redirects. For this reason, anyone making a WebFinger request should take care to limit the maximum number of redirects that they follow.
The current use of WebFinger with ActivityPub could be improved in several ways:
preferredUsername
is not ideal for constructing WebFinger addresses, and it also does not allow for expressing actual "preferred usernames". An explicit property for denoting the user's "canonical" WebFinger address would ease reverse-discovery concerns.Accept
header specifies the correct media type, skipping the resolution of the JRD.