WebFinger Split-Domain Canary

Hi! This is the website of the WebFinger Split-Domain Canary, and also the place where you land if you try to open the ActivityPub profile on its original server. Welcome and thank you for coming by! You’re invited to jump to one of the following sections:

A stylized cartoon drawing of a rotund flying yellow bird with wide open eyes.

Summary

Alright, let me explain what this is about – in a few more words than the profile description, but a lot less than I could use.

Information for Users

You may have already heard that fediverse platforms like Mastodon, Misskey, Akkoma, or GoToSocial use the ActivityPub protocol to exchange social data such as posts, follows, likes, boosts, and more. The only thing you really need to know about ActivityPub for the purpose of this project is that it identifies people not with any sort of @-decorated username, but by specific internet addresses that point at a spot on their instance where their profile information is stored. For example, the ID for the Mastodon project’s account on mastodon.social is as follows:

https://mastodon.social/users/Mastodon

ActivityPub on its own has no notion of unique user names or of tagged user mentions. To create those, people had to first invent a way to write them (“at person at server” caught on), and then they had to come up with a way to reliably get from a combination of a server name and a user name to the user’s correct ActivityPub ID.

This is what the WebFinger protocol is used for. The idea of it is simple enough: it defines a standardized way to ask a server for basic information about a specific user. WebFinger is what enables your fediverse platform to take your mention of a username or your search query and basically be like, “Hey server example.com, I’ve been told you have a user named alice, how and where can I get their profile information?” In return, one of the things it receives is the user’s ActivityPub ID, which it can then fetch for detailed profile information. For most fediverse profiles, their WebFinger server (the server name in their handle) is the same as their ActivityPub server.

Something that’s nice about WebFinger is that it is technologically very simple. An experienced web developer can fully understand and implement WebFinger in less than an afternoon, which is something that cannot be said for ActivityPub. If you’re a small-time web developer with a personal site, adding WebFinger support to it is something that may very well be in your reach. So, one might be tempted to split the WebFinger and ActivityPub duties between different servers: you could have one server provide your user handle (maybe on your custom domain that also hosts your blog) and have your full ActivityPub profile be hosted by someone else on a completely different domain.

It turns out that yes, you can do that, and some people do it! The combination of WebFinger and ActivityPub lets you achieve things like having multiple different user handles on different domains all point to the same profile. Mastodon even supports cases where a profile’s handle does not correspond to its ActivityPub server at all, and instead the profile can only be mentioned using its custom WebFinger domain.

This type of configuration is what this website is about. Because while Mastodon supports it fairly well, some other ActivityPub platforms struggle with it, and their developers may not even know about it. This Canary is a clear example you can point to for this type of split-domain configuration, and platform developers can use it for diagnosis and testing.

The full handle for this account’s profile is:

@canary@correct.webfinger-canary.fietkau.software

However, its ActivityPub profile resides on a different hostname. Its ActivityPub ID (which, generally speaking, you should never see during normal use) is the following:

https://wrong.webfinger-canary.fietkau.software/canary

So if you load the Canary’s profile on your own instance and you see the “wrong” name in its handle, you know that the platform software you’re using is not handling this use case correctly. I would like to see support for this kind of configuration improve wherever it isn’t fully implemented yet, so people can more easily use their custom domains in their fediverse handles. I hope we can make that happen, and as a developer, I’m willing to help where I’m able!

In the meantime, what you and I can do is spread the word. Boost the Canary’s post if you agree with its goal, talk to ActivityPub platform developers in your social circle about it, and see if we can improve the support for split-domain setups in the fediverse.

Information for Developers

Hi! If you’re reading this, odds are you were directed here by someone who noticed that the ActivityPub platform you’re building has issues with split-domain configurations on remote actors. I hope they were polite about it, and sorry if this is about to add to your workload.

For this section, I’m going to assume you’re broadly familiar with the inner workings of ActivityPub and WebFinger. You’ve built a working fediverse platform after all. If you need to refresh your memory of the basics, you can read the section above this one.

When it comes to support for split-domain configurations in AP platforms, there are two levels we need to differentiate:

  1. Supporting split-domain configurations for remote actors (i.e., displaying affected profiles correctly)
  2. Supporting split-domain setups for your own platform and presenting local profiles to the fediverse accordingly

The second level is largely irrelevant for the purpose of this document. The capability to run a split-domain setup is one optional fediverse feature of many that you’re free to offer or not offer, so in that regard it’s not necessary for interoperability.

Fulfilling the first level, however, is required in order to correctly show external profiles that make use of split-domain setups. If you’re not aware of the possibility, your software may be showing wrong information to local users. With split-domain setups being used by a number of servers in the wild, fulfilling level 1 is arguably required for full interoperation with the current fediverse.

I should note that the structure of split-domain setups is not formally specified. Their possibility of existence emerges from the interaction between WebFinger and ActivityPub, and their behavior is largely driven by a loose consensus of implementations rather than adherence to a specification. However, since July 2024 there is a SocialCG Community Report “ActivityPub and WebFinger” that details the interaction and discovery between these two standards a bit more formally than this text. (There is also FEP-2c59 advocating for a webfinger property on ActivityPub actors, but this does not seem to be widely implemented.)

What’s a Handle Anyway?

The central misconception that we need to unambiguously clear up is the assumption that the hostname in a fediverse account’s handle (double-@ form) must correspond to the one in its ActivityPub actor ID, or in other words, that the hostname of the actor’s URI would necessarily determine the handle. This is not the case. Converting an actor ID to a fediverse handle always requires at least one WebFinger lookup (assuming you don’t have the result cached yet). The hostname in a fediverse handle is what GoToSocial’s documentation calls the “account domain”, as opposed to the “host domain” where the AP software is running and which appears in actor IDs (Mastodon’s documentation calls these “local domain” and “web domain” respectively). The account domain does not need to do much except respond to WebFinger requests with the correct information for the account.

For added clarity, we need to differentiate between having a split-off account server and using one-sided WebFinger redirects:

An interesting consequence of the way these standards work is that a single fediverse actor may have any number of working handles. You can set up WebFinger on your own domain to redirect to your Mastodon account and it will enable people to search for your custom-domain handle to find your account on an entirely different domain. However, in this type of setup the “canonical” handle is still the one provided by your Mastodon server, and it’s the one that will be shown on the profile. So while you can have any number of WebFinger servers redirect to an ActivityPub actor without that actor’s platform having to cooperate or even be aware of them, their utility is limited. In a split-domain configuration, the actual canonical handle contains an account domain that’s different from the host domain. For reasons detailed below, this cannot be done without the cooperation of the AP platform.

Note that the only identifier that can reliably determine the identity of an account is the ActivityPub ID. Both parts of the handle, the user name and the handle domain, may change over the lifetime of an account. As recommended by the SocialCG, implementations should not rely on the handle to identify or deduplicate accounts.

From Handle to Actor ID

If you have an account handle such as @alice@example.com, how do you convert that to an ActivityPub actor ID? You split off the server name, perform a WebFinger request by fetching https://example.com/.well-known/webfinger?resource=acct:alice@example.com (or if you want to be thorough, check host-meta first to see if the server has its WebFinger URI somewhere else), and see what you get. If example.com is a working fediverse account server, this will give you some basic account information including the ActivityPub actor ID. Note how the account domain appears twice in the URL, once as the actual hostname and again as part of the resource parameter. This may seem redundant at a glance, but we’re about to see why it’s important.

This is pretty difficult to get wrong and I have not seen any mature fediverse platform fail this process.

From Actor ID to Handle

The other direction happens when your platform gets incoming activities (such as a like or a follow) from a remote actor. You receive their ID – let’s say it’s https://social.example.org/users/bob – and now you want to find out their (canonical) handle so you can display the profile and let your local users interact with it.

The first step is to fetch the ActivityPub profile from its ID if you don’t have the full data yet. Next, check the profile data for the presence of a preferredUsername. It is not a mandatory part of an ActivityPub actor, so https://social.example.org/users/bob may not have one. In that case, it also does not have a handle. Mastodon refuses to interoperate with actors that do not have a preferredUsername, so this case is probably pretty rare in practice. Let’s assume you find a preferredUsername of bob. This may or may not resemble whatever identifier is used in the actor ID.

Next, you perform a WebFinger lookup of the preferredUsername on the remote actor’s AP server, which in this case would look like this: https://social.example.org/.well-known/webfinger?resource=acct:bob@social.example.org. You check the WebFinger response for the subject key. If the subject is acct:bob@social.example.org, identical to the parameter you sent, then congrats, you’re done! This AP server does not use a split-domain configuration and you have confirmed that Bob’s handle is @bob@social.example.org.

The interesting case is if the returned subject contains a different domain. Let’s say that the previous WebFinger request returns a subject of acct:bob@example.org (note the different hostname). In this case it is a WebFinger redirect and you need to make a second WebFinger request, now to the domain you just discovered: https://example.org/.well-known/webfinger?resource=acct:bob@social.example.org This should return an identical result, i.e. the subject should still be acct:bob@example.org. This confirms that you have discovered the canonical handle. To avoid issues with account impersonation, it is prudent to compare the ActivityPub ID provided in this WebFinger response to the one you started with – if they don’t match, something strange is going on.

Implementation Status

This overview is an attempt to summarize the availability of and interoperability with split-domain setups in various ActivityPub platforms. The selection here is not based on popularity, but only on the availability of dependable information. To offer corrections or to get your own platform listed, please contact me.

Software Checked version For remote actors For local actors Note
Akkoma 3.13.2 Yes Yes One handle domain for all users. Docs
Bridgy Fed N/A No N/A Bridge service with no local accounts, split-domain awareness affects how bridged handles are displayed. #1031, #1638
Fedify 1.1.2 Yes No Remote actors are correctly handled. Currently no support for local split-domain setups.
Friendica 2024.08 No No No support for local or remote split-domain setups. #5895
GoToSocial 0.17 Yes Yes One handle domain for all users, handle domain cannot be changed after initial setup, the host domain must be a subdomain of the handle domain. Docs, #2106
Iceshrimp 2024.1-beta3 (.net), 2023.12.9 (js) Yes Yes One handle domain for all users. Docs
Mastodon 4.3.1 Yes Yes One handle domain for all users, handle domain cannot be changed after initial setup. Docs, #2668, #5167
Misskey 2024.10.1 No No No support for local or remote split-domain setups. #7922
Pleroma 2.7.0 Yes Yes One handle domain for all users. Docs, #1469
Pixelfed 0.12.3 No No No support for local or remote split-domain setups. #3563
Seppo 0.5 No No No support for local or remote split-domain setups.
Sharkey 2024.8.2 No No No support for local or remote split-domain setups. #390
snac2 2.61 No No No support for local or remote split-domain setups. #3
Takahē 0.11.0 Yes Yes Supports multiple handle domains per installation. Docs

About this Project

This project resulted from minor frustrations I experienced while examining and fixing interoperability issues between my own ActivityPub implementation (which, stripped down to some minimal scaffolding, also powers this account!) and other existing platforms. My assumption that the Mastodon’s ability to parse remote split-domain setups would be broadly present in other software, proved to be unfounded. This project is intended to provide a single-page explainer (including relevant links) to ease getting users and implementers on the same page.

While I am in part motivated by seeing one of my fediverse projects not handled as correctly by some ActivityPub software as I had hoped, I genuinely don’t mean this from a place of entitlement. I hope we can all treat this as a harmless pointer towards a type of configuration some platforms may have overlooked. It’s never easy to predict the potential spread of something like this ahead of time, but if against all odds I see a deluge of negative comments towards platform developers in its wake, I will take it down.

Essentially, this Canary project is a tiny ActivityPub server hosting only one profile. Because all the information is on the public profile, it does not need to do anything with federated messages. Replies, likes and boosts can all still happen, but this script itself doesn’t keep track of them, so they’re mostly only seen by people who share a server.

Source Code

If you’d like to host your own copy of this or use it as an ActivityPub learning opportunity or whatever else, you are free to take the source code and run with it! I have released it under Creative Commons Zero 1.0, meaning it’s as close to public domain as I can put it. You can download this instance’s live source code (nifty, huh?) or you can find the latest version on my website, which will hopefully exist for a good long while.