Aliasing your Mastodon handle

• 11 min read

Using a custom domain to alias your Mastodon handle.


I’m not very active on social media, but I recently created a Mastodon account.

I’m still learning about the fediverse. So I was reading the docs a bit, and that’s when I stumbled upon WebFinger.

I never heard of it before, but Mastodon uses WebFinger to figure out the location of an account. So it can for example resolve the account danillouz@mastodon.social to the location https://mastodon.social/@danillouz.

This location information is returned by a WebFinger endpoint. And this made me wonder. Could my site, hosted on a custom domain, return this information as well, so that I could use my custom domain as an “alias” for my Mastodon handle? Turns out you can! But there are some caveats.

What’s WebFinger?

WebFinger is a protocol1 that allows information about people or entities to be discovered over HTTP. It basically resolves some sort of URI identifier (like an email address, Mastodon account, or phone number) to a location (i.e. an URL), which can be retrieved by making a WebFinger request.

Making a WebFinger request

A WebFinger request is an HTTP GET request to a resource. The resource is a well-known URI with a query target. And the query target identifies the entity to get the location for, which is specified via the ?resource= query parameter in the request. The endpoint then returns the location information as JSON.

For example, to get WebFinger information for the Mastodon account danillouz@mastodon.social2, you need to make an HTTP GET request to:

https://mastodon.social/.well-known/webfinger?resource=acct:danillouz@mastodon.social

Which will return the following JSON response:

{
  "subject": "acct:danillouz@mastodon.social",
  "aliases": [
    "https://mastodon.social/@danillouz",
    "https://mastodon.social/users/danillouz"
  ],
  "links": [
    {
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html",
      "href": "https://mastodon.social/@danillouz"
    },
    {
      "rel": "self",
      "type": "application/activity+json",
      "href": "https://mastodon.social/users/danillouz"
    },
    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://mastodon.social/authorize_interaction?uri={uri}"
    }
  ]
}

You can replace the Mastodon domain and username with your own, to get your information instead:

https://{MASTODON_DOMAIN}/.well-known/webfinger?resource=acct:{MASTODON_USERNAME}

Why is WebFinger used?

On Mastodon, users have accounts on different servers. Like mastodon.social or mas.to. So even though the handles danillouz@mastodon.social and danillouz@mas.to share the same “local” username danillouz, they are different accounts.

And from what I understand, Mastodon’s internal implementation can’t just use the account handle. It requires the location (provided by WebFinger) to convert an account to a user on its server for things like mentions and search to work.

Adding a WebFinger endpoint

The RFC mentions that WebFinger information is static:

The information is intended to be static in nature, and, as such, WebFinger is not intended to be used to return dynamic information like the temperature of a CPU or the current toner level in a laser printer.

So if you can host some static JSON on your custom domain, you can add a WebFinger endpoint.

You can do this by:

  1. Making a WebFinger request for your Mastodon account to get your WebFinger information.
  2. Copy-and-pasting the WebFinger JSON response from step 1 to a static file.
  3. Returning the JSON3 from step 2 whenever an HTTP GET request is made to /.well-known/webfinger?resource=acct:{MASTODON_USERNAME} on your custom domain.

With that in place, your custom domain can be used to find your Mastodon account.

Static file endpoint

I’m using Astro, so I just added a static file endpoint by creating the file:

src/pages/.well-known/webfinger.json.ts

With the following content:

import type { APIRoute } from "astro"

const MASTODON_USERNAME = "danillouz"
const MASTODON_DOMAIN = "mastodon.social"

export const get: APIRoute = async function get({ params, request }) {
  return {
    body: JSON.stringify({
      subject: `acct:${MASTODON_USERNAME}@${MASTODON_DOMAIN}`,
      aliases: [
        `https://${MASTODON_DOMAIN}/@${MASTODON_USERNAME}`,
        `https://${MASTODON_DOMAIN}/users/${MASTODON_USERNAME}`,
      ],
      links: [
        {
          rel: "http://webfinger.net/rel/profile-page",
          type: "text/html",
          href: `https://${MASTODON_DOMAIN}/@${MASTODON_USERNAME}`,
        },
        {
          rel: "self",
          type: "application/activity+json",
          href: `https://${MASTODON_DOMAIN}/users/${MASTODON_USERNAME}`,
        },
        {
          rel: "http://ostatus.org/schema/1.0/subscribe",
          template: `https://${MASTODON_DOMAIN}/authorize_interaction?uri={uri}`,
        },
      ],
    }),
  }
}

Redirecting WebFinger requests

Note that the static JSON endpoint I added will only serve the WebFinger information when making an HTTP GET request to:

https://www.danillouz.dev/.well-known/webfinger.json

But Mastodon will actually make an HTTP GET request to:

https://www.danillouz.dev/.well-known/webfinger?resource=acct:danillouz@mastodon.social

Since I have just one Mastodon account, I chose to just ignore the ?resource= query parameter, and redirect all requests from /.well-known/webfinger to /.well-known/webfinger.json.

I’m using Vercel, which supports redirects by creating a vercel.json file. So I can achieve the desired redirect by adding the following rule:

{
  "redirects": [
    {
      "source": "/.well-known/webfinger",
      "destination": "/.well-known/webfinger.json"
    }
  ]
}

Using my custom domain as an alias

Now that my custom domain has a WebFinger endpoint, I can find my Mastodon account by using my custom domain!

For example, searching for hi@danillouz.dev will now give me a hit:

Mastodon search results, showing a search hit after searching for hi@danillouz.dev.

Searching for hi@danillouz.dev finds the Mastodon account danillouz@mastodon.social.

So how useful is this?

I’m not sure to be honest.

Like mentioned before, Mastodon is a bit different, where an account handle consists of two parts:

  • The local username. For example danillouz.
  • The server domain. For example mastodon.social.

And the docs mention that you should include the server domain when sharing your handle with other people, because otherwise they won’t be able to find you easily:

Mastodon allows you to skip the second part when addressing people on the same server as you, but you have to keep in mind when sharing your username with other people, you need to include the domain or they won’t be able to find you as easily.

So in theory, setting up an alias allows you to create a handle that does not change when migrating to a different Mastodon server. And it might make your account easier to find if people know your custom domain.

It’s also pretty cool that with the alias you can have a Mastodon handle that includes your custom domain without needing to host your own Mastodon server. But practically speaking, searching for just the local username on different servers also works as far as I can tell.

When the docs mentioned that you should include the server domain when sharing your handle (because otherwise people won’t be able to find you easily) I thought this meant that someone would always have to search for danillouz@mastodon.social on servers other than mastodon.social to find me. But this doesn’t appears to be the case. For example, I can search for danillouz on mast.to, and it will find me.

So maybe, aliasing your handle isn’t really a good idea?

I’m not sure if having an “extra” WebFinger endpoint can actually break stuff (can information become stale?). But there are some caveats when using your custom domain as an alias to be aware of.

Caveats

There might be more, but these are the ones I encountered.

Users need to be signed in to find you via the alias

I created my account on mastodon.social, and there I can find my account when searching for the alias without problems. But when I tried finding my account using the alias on a different server, I was surprised there was no result.

Turns out that when you’re not signed in to a server, the search API will not use WebFinger to resolve the handle!

This is how the search request looks like when I’m signed in:

https://mastodon.social/api/v2/search?q=hi@danillouz.dev&resolve=true

And this is how the same search request looks like when I’m signed out:

https://mastodon.social/api/v2/search?q=hi@danillouz.dev&resolve=false

The difference is that the query parameter resolve is set to true when signed in. But is set to false when signed out.

And checking the v2 search API docs, we can see that resolve controls if a WebFinger lookup should happen or not:

Boolean. Attempt WebFinger lookup? Defaults to false.

The alias behaves like a “catch-all”

Since I’m redirecting WebFinger requests, I’m returning the same response for all acct: queries. So any4 local username can be provided together with my custom domain.

For example, these all work:

  • hey@danillouz.dev
  • 737@danillouz.dev
  • lol@danillouz.dev

In closing

It was fun to learn a bit more about Mastodon’s internals. And while searching around how Mastodon uses WebFinger, I saw others had the same idea to alias their handle. Like Maarten Balliauw and Lindsay Wardell.

I think the latter post is pretty cool, where Lindsay is fetching Mastodon posts via RSS to show them on their site. I learned that you can postfix any account or tag with .rss, and Mastodon will give you the RSS feed for it! This reminded me of the Reddit API. So I tried postfixing with .json, and that also works5.

For example:

I especially like the RSS feed functionality, since that allows me to subscribe to accounts and tags from my favourite RSS reader6!

Footnotes

  1. RFC 7033 describes the WebFinger protocol.

  2. Mastodon uses the acct: URI scheme as described in RFC 7565.

  3. The WebFinger RFC mentions that the Content-Type of a WebFinger response should be application/jrd+json. But it looks like using application/json also works.

  4. Sadly, using emoji doesn’t work though.

  5. But as far as I can tell, you won’t get the posts in JSON for an account.

  6. If you’re not familiar with RSS, have a look at aboutfeeds.

Webmentions

Loading...


Thanks for reading! If you have any remarks or ideas on how to improve this post, please let me know on GitHub .

Post last updated .