/webfinger-astro

Implement a WebFinger endpoint in Astro

August 26th, 2024
· 5 min read ·
Code
Astro
Fediverse

With the use of the WebFinger protocol, you can make your Mastodon account discoverable via your own domain. Without hosting a separate Mastodon instance.

For example, my Mastodon account is [email protected]. But when you search for [email protected], you’ll also find my profile1.

Here’s how you can add this functionality relatively easy to your own Astro site. The approach also works for other frameworks, the specific code just might look a bit different. You can always reach out to me, and I’ll see, how I can support you!

Preparation

Your Mastodon instance gives you the exact JSON, you need for this to work. Just go to https://[your_instance]/.well-known/webfinger?resource=acct:[your_username]@[your_instance] and you should be greeted with a JSON object. Mine is for example under https://mastodon.design/.well-known/webfinger?resource=acct:[email protected].

Save both the link and the JSON response somewhere, we’ll need it later.

Static method

This method uses a static Astro endpoint. This means that it will ignore anything that comes after the ? in the url and always serve the same JSON. So [email protected] will work, just as [email protected] or [email protected] will.

We will have to follow the same directory structure as Mastodon, though.

So in your src/pages folder, create the .well-known directory (with the dot!) and add a webfinger.ts file within.

This file then contains the JSON you copied earlier and a GET function, that just serves that JSON when someone (or something, like Mastodon) looks for your WebFinger.

Here’s a template for you to copy:

// Endpoint for WebFinger
const WEBFINGER_JSON = {} // replace {} with your full JSON object

export async function GET() {
  return new Response(JSON.stringify(WEBFINGER_JSON), {
    headers: {
      "Content-Type": "application/activity+json",
    },
  });
}

You can now open https://localhost:4321/.well-known/webfinger?resource=acct:[email protected] and should see your JSON object on screen.

Dynamic method

The dynamic version is just a bit more complicated to implement, but has the added benefit of allowing you to specify multiple users on your domain. So you could create a [email protected] as well as a [email protected] user for your Pixelfed account. This is possible because the endpoint now respects the resource parameter after the ? in the url.

It only works though, if you deploy your project in server or hybrid mode. You can find more infos about this in the Astro docs.

Just like with the other method, we need to create the webfinger.ts file within the src/pages/.well-known directory.

The file then looks something like this:

// Endpoint for WebFinger requests
export const prerender = false;

// Edit this array
const ACCOUNTS = [
  {
    username: "toots",
    redirect:
      "https://mastodon.design/.well-known/webfinger?resource=acct:[email protected]",
  },
  // ... more users here
];

const hostname = "yourdomain.com";

export async function GET({ request, redirect }) {
  const url = new URL(request.url);
  const resource = url.searchParams.get("resource");

  if (!resource) {
    return new Response("Bad request", { status: 400 });
  }

  for (const account of ACCOUNTS) {
    if (resource === `acct:${account.username}@${hostname}`) {
      console.log(account.redirect);
      return redirect(account.redirect, 301);
    }
  }

  return new Response("Not found", { status: 404 });
}

One thing that is crucial is that you put export const prerender = false; at the top of the file if you have set your output in your astro.config.mjs file to hybrid.

You can then add as many users in your ACCOUNTS array as you please. Just remember that the redirect has to be the .well-known link from Mastodon (or another Fediverse platform) you copied earlier.

When Mastodon now reaches out to your server to look for [email protected], this function will resolve this user to the appropriate redirect and thus return the correct JSON.

If someone is looking for [email protected] a 404 error will be returned.

That’s already it, now you have Mastodon on your own domain without hosting a server! If you need some further help, take a look at the source code of this website or reach out to me. I’m happy to assist you in setting this up.

Further reading

Here are some other articles that helped me along the way that might serve you as well:

Footnotes

  1. This unfortunately doesn’t work in some Mastodon clients like Ivory. The official apps/websites work perfectly though.

  2. This post was helpful for my understanding, the package didn’t work in my setup unfortunately.

What are your thoughts on this post?

I’d love to hear from you! Please write me an email by clicking this link (I reply to every email I receive!).

If you're on Mastodon, interact with this post and your reaction will appear below after some time.

Public reactions to this post

  • commented on this on

    @dominik What would happen if you migrated to another server? Won't it confuse remote servers or even break federation?

  • commented on this on

    @jasdemi Not much because this doesn't really do anything to your profile. It's essentially just a fancy alias for better discovery, not a “real” Mastodon user.

    The only thing you had to do was point the redirect to the new server. But then it should work properly again.

  • commented on this on

    @dominik I wish Astro would just let us use the query parameter in the getStaticPaths() function. That way you could still use the dynamic option but without having to enable hybrid mode.

    Anyway, thanks for sharing!

    Do you use Astro in hybrid mode? I noticed you have the interact on Mastodon system for comments. If you’re running statically, how do you go about getting the Mastodon post URL into the markup?

  • reposted this on
  • liked this on
  • commented on this on

    @dominik This is really cool, thanks! Looking at the webfinger.ts logic, instead of having multiple pseudo-accounts, I guess you could have 1 default, and then add others depending on the referring server/service? Although, I can't see anything about referrer in the WebFinger spec, nor can I think of a good use-case other than...chaos.