Are actors and webfingers 1 to 1?

If they’re not 1:1, how do you go from webfinger to actor, or vice versa?

On the mastodon beginners tutorial, they make an actor with the username “Alice.” There’s no link to any webfinger in the actor, but the server does have a webfinger also named “Alice,” thus making it usable. Does this mean that it’s impossible to have an actor that uses another server’s webfinger? What if you wanted multiple actors be able to post under the same name?

Having it be 1:1 would simplify quite a bit, but it also seems somewhat limiting. Please explain.

Lemmy is a good example here, as users and communities may in fact use the same name and the webfinger is therefore ambiguous as to whether you meant the user or the community. For instance, this is what https://lemmy.world/.well-known/webfinger?resource=acct:news@lemmy.world gives:

{
  "links": [
    {
      "href": "https://lemmy.world/u/NEWS",
      "rel": "http://webfinger.net/rel/profile-page",
      "template": null,
      "type": "text/html"
    },
    {
      "href": "https://lemmy.world/u/NEWS",
      "properties": {
        "https://www.w3.org/ns/activitystreams#type": "Person"
      },
      "rel": "self",
      "template": null,
      "type": "application/activity+json"
    },
    {
      "href": null,
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://lemmy.world/activitypub/externalInteraction?uri={uri}",
      "type": null
    },
    {
      "href": "https://lemmy.world/c/news",
      "rel": "http://webfinger.net/rel/profile-page",
      "template": null,
      "type": "text/html"
    },
    {
      "href": "https://lemmy.world/c/news",
      "properties": {
        "https://www.w3.org/ns/activitystreams#type": "Group"
      },
      "rel": "self",
      "template": null,
      "type": "application/activity+json"
    }
  ],
  "subject": "acct:news@lemmy.world"
}

As you can see, there is both a user called news (https://lemmy.world/u/NEWS) and a news community (https://lemmy.world/c/news). They are differentiated via the extra type property, although I’m not sure how well that is supported by other implementations.

1 Like

Sidenote: that tutorial is from 2018 and has basically never been updated. Take anything it says with the context that it may be (is) outdated.

Actual answer:

Specifically, there is no “webfinger also named Alice”, but what you can do is use WebFinger to look up the resource acct:alice@domain.example. It should respond with a JSON Resource Descriptor (JRD) that has a links array, where one of the items in the array is a JSON object that has rel being self, and type being the ActivityStreams media type. The href of that item should link back to the actor that you started at.

This process is called “reverse discovery” in the “ActivityPub and WebFinger” report by the SocialCG, which is currently in the process of being published: ActivityPub and WebFinger

I’d also advise reading the rest of that report if you want to know more.

WebFinger is primarily useful in going from a username@example.com identifier to some ActivityPub actor. Once you get to the ActivityPub actor, you pretty much don’t need WebFinger anymore, although you can generally reconstruct an acct: URI by combining the preferredUsername and the hostname of the id. (At least, this is the expectation.)

In many but not all cases, the mapping is 1:1. In fact, several implementations assume it to be 1:1. It’s not semantically clear what it means for an acct: URI to have a self link relationship to two different ActivityPub actors. It’d be a bit like trying to serve two different HTML documents when making an HTTP request against the same URI – the URI is only ever supposed to represent one resource. Still, this hasn’t stopped some implementers from trying to use the self relationship to refer to two fundamentally different resources, resulting in a situation where you are claiming A = B, and A = C, but in reality B =/= C. For example, what Lemmy does is highly irregular and arguably violating the meaning of self. But if you want to support Lemmy, you need to deal with this violation somehow. Somewhat luckily, they include properties on each self-link, where a property of https://www.w3.org/ns/activitystreams#type will have a string literal value of either Person or Group. Now, there are several problems with this, not least of which is that there is no such thing as https://www.w3.org/ns/activitystreams#type – in reality, type is an alias for JSON-LD @type, which is an alias for the RDF property http://www.w3.org/1999/02/22-rdf-syntax-ns#type in the same way that Turtle’s a is an alias for the same predicate. Not pretty, and not semantic, but I guess it works for them, at least?

This is also covered in a different section of the above-cited CG report: ActivityPub and WebFinger

Isn’t the fundamental problem that ActivityPub says that preferredUsername explicitly has no uniqueness guarantees? So actually ActivityPub explicitly says conflicting usernames are allowed, which makes it seem like microsyntax like @username@example.com is inherently ambiguous and it seems like WebFinger has no mechanism for disambiguating which actor you mean.

Many implementations have the preferredUsername in the ActivityPub ID of the actor, which makes it unique and immutable, but an implementation could choose to just use an opaque ID without referencing the preferredUsername and then two different actors with different ActivityPub IDs could easily have the same preferredUsername.

It seems like WebFinger is just kind of not compatible with ActivtyPub since ActivityPub has no unique usernames while WebFinger kind of assumes unique usernames, as far as I understand. It’s honestly a bit of a weird situation.

The fundamental problem isn’t ActivityPub or WebFinger. The fundamental problem is that an acct: URI is not meant to be resolved. It represents an account on anything with an “account” system. Typically but not always, this is a networked machine made available on some FQDN or hostname and serving as a host for those accounts. Per RFC 7565: The 'acct' URI Scheme

not all service providers offer email services or web interfaces on behalf of user accounts (e.g., a microblogging or instant messaging provider might not offer email services, or an enterprise might not offer HTTP interfaces to information about its employees). Therefore, the participants in the discussion recognized that it would be helpful to define a URI scheme that could be used to generically identify a user’s account at a service provider, irrespective of the particular application protocols used to interact with the account. The result was the ‘acct’ URI scheme defined in this document.

Imagine there’s a Unix system running on a certain hostname. It has a Web server, an XMPP server, an email server, and so on. Each of those accounts exist locally as a Unix account with a username. Now, how do you represent or refer to the Unix account with username a? Locally, you might do that with acct:a. In a global network, you have to qualify that with a host-part or domain-part, and it becomes acct:a@trwnh.com. But this account acct:a@trwnh.com is not necessarily “the same” as any given Web resource, or any given XMPP resource, or any given SMTP etc etc etc. If it was the same, then you could declare that acct:a@trwnh.com has one or more aliases. And by logical extension, you could also declare every single item in the union set of subject + aliases to be related to the current subject via the self link relationship. You could also declare the subject to be a canonical link relation. So you might end up with something like this, when queried via WebFinger for more information:

GET /.well-known/webfinger?resource=acct:a@trwnh.com HTTP/1.1
Host: trwnh.com
{
  "subject": "acct:a@trwnh.com",
  "aliases": ["mailto:a@trwnh.com", "xmpp:a@trwnh.com"],
  "links": [
    {"rel": "self", "href": "mailto:a@trwnh.com"},
    {"rel": "self", "href": "xmpp:a@trwnh.com"},
    {"rel": "self", "href": "acct:a@trwnh.com"},
    {"rel": "canonical", "href": "acct:a@trwnh.com"}
  ]
}

Now, what’s the problem with the last two links? Well, acct: doesn’t resolve. You can’t dereference an acct: URI. RFC 7565 warns about this (emphasis mine): RFC 7565: The 'acct' URI Scheme

the scheme is designed for the purpose of identification instead of interaction (regarding this distinction, see Section 1.2.2 of [RFC3986]) […] It is not assumed that an entity will necessarily be able to interact with a user’s account using any particular application protocol, such as email; to enable such interaction, an entity would need to use the appropriate URI scheme for such a protocol, such as the ‘mailto’ scheme […] Because an ‘acct’ URI enables abstract identification only and not interaction, this specification provides no method for dereferencing an ‘acct’ URI on its own, e.g., as the value of the ‘href’ attribute of an HTML anchor element. For example, there is no behavior specified in this document for an ‘acct’ URI used as follows:

<a href='acct:bob@example.com'>find out more</a>

Any protocol that uses ‘acct’ URIs is responsible for specifying how an ‘acct’ URI is employed in the context of that protocol (in particular, how it is dereferenced or resolved; see [RFC3986]). As a concrete example, an “Account Information” application of the WebFinger protocol [RFC7033] might take an ‘acct’ URI, resolve the host portion to find a WebFinger server, and then pass the ‘acct’ URI as a parameter in a WebFinger HTTP request for metadata

And this is exactly what Mastodon ended up doing: construct an acct: URI and plug it into WebFinger to get an appropriate link to the resource you’re actually after. Back then, Mastodon used OStatus, which was built on Atom and XML. Convention in an Atom feed was to include a self link within the response, so that any consumer could get the identifier of the current atom+xml document. In JSON-LD today, you would use the @id property for the exact same purpose. But Mastodon wanted user@domain handles, so they just lifted the self link out of the Atom and put it into the WebFinger JRD. Which was not ideal, from a semantic perspective, but it works as long as you declare the appropriate aliases, and there was a 1:1 mapping between “protocols” (to the extent that “WebFinger resolution of an acct: URI” can be called a “protocol”). Again, A == B, B == A, basic equality.

If you really wanted to simplify the fediverse’s usage of WebFinger, you could just define an extension to WebFinger. Say that the 1:1 mapping is required, and put an Accept header with the activitystreams media type on your request to the WebFinger endpoint. If the WebFinger server sees that header, it will return an AS2 document instead of a JRD.

So all this is kind of the consequence of using an identifier that wasn’t meant to be interacted with… in a way that interacts with it. Yes, it’s weird. That’s what happens when you use something in a way it wasn’t meant to be used.