What is the current spec for remote follow?

I know this will start a conversation about how this should work, but I’d like to restrict this to the facts: how does it work?

I’ve implemented what I believe to the correct flow for remote follows:

  1. You use Webfinger to look up the remote server’s follow action URL template.
  2. You direct the user to this URL, replacing the template placeholder with the actor to be followed. For example: https://mastodon.social/authorize_interaction?uri={uri}
  3. The redirect to this URL takes place and the user can take action.

But it’s here, where with Mastodon, I receive the error:
"Unfortunately, there was an error looking up the remote account"

I see the remote server making a successful request to the actor’s IRI on my server, so the flow looks to be successful, however this catch-all error happens anyway.

Does anybody have the spec of what is needed to make this work?

In which format have you added the uri? In Friendica we just use the url-encoded contact url and not the handle. For Mastodon accounts you have got three different representations:

  • https://domain.tld/users/user
  • user@domain.tld
  • https://domain.tld/@user
    You have to use the first format. I’m unsure if it works for the other formats as well.

Yeah, that’s the same I’m doing. The URI is the full ActivityPub actor’s URL, and the remote server is successfully requesting it. So I’m assuming there’s something specific missing in my actor’s response, but I couldn’t come up with anything. So that’s why I was curious if there was a spec I could reference to find out what the remote server (in this case Mastodon) is looking for that I might be missing.

I know this screenshot isn’t terribly helpful, but it just shows that Mastodon is successfully making a request to the resource that it’s trying to get the info of.

Going to sign up for a Friendica account and try it with that!

Ah ha! Friendica gives a more helpful message:

The network type couldn’t be detected. Contact can’t be added.

@heluecht In this case with Friendica, what is looking for to determine the “network type”?

the system is performing a webfinger request, also it tries to fetch the profile URL. If you provide me with your profile url, I can check it - but I only later this days, since currently I’m away.

Hi,

There is no such thing as a spec for Remote Follow, it is implementation-defined and is one of those things from GnuSocial/OStatus-era which didn’t get standardized into ActivityPub.

I would strongly suggest to not use Remote Follow or try to replicate it’s behavior as it works like phishing: Stating your account on another platform and hopefully being sent to your actual instance for the Follow.

Putting a link to the ActivityPub id, why not formatted like a webfinger address (which is an extension of the spec) should be the way to go, ActivityPub implementations tend to allows to paste the link into the search field.

Another other way it could be done would be via custom-schemes (ie. activitypub://follow/$id), sadly browsers are terrible and tend to not allow to pick handlers dynamically, good luck with WHATWG I guess.

@heluecht I appreciate that!

So this is what I get after the redirect, showing that it fetched the correct Profile URL from the Webfinger request:

image

So maybe there’s something specific in this profile that is missing or invalid:

https://ap-test2.ngrok.io/federation/user/testing2

Hmm, that address looks fine to me. I was able following it. Possibly you changed something or venera.social had got a problem.

Oh weird! Well that’s good to know I’m not crazy and you were able to see the remote follow work. Maybe these other servers I’ve been testing with have something cached from previous testing, too.

I appreciate you trying it out and letting me know!

Here’s what definitely works with Mastodon.

GET https://friends.grishka.me/.well-known/webfinger?resource=acct:grishka%40friends.grishka.me

That returns this:

{
  "subject": "acct:grishka@friends.grishka.me",
  "links": [
    {
      "rel": "self",
      "href": "https://friends.grishka.me/users/1",
      "type": "application/activitypub+json"
    },
    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://friends.grishka.me/activitypub/externalInteraction?uri={uri}"
    }
  ]
}

I believe this exact structure is required, and the rel field is especially important. Also make sure that you’re setting Content-Type to something sensible like application/json.

I feel like I have everything in place, but the cryptic errors continue on the remote side.

I just realized I should probably be more clear. When I talk about “Remote Follow” I mean this flow.

  1. You click a “Follow” button on a site.
  2. A page displays asking you to type in your Fediverse account.
  3. You get redirected to the remote Fediverse server.
  4. You get prompted to accept the follow action.

Example of this flow failing:
remotefollow

I think the webfinger is working fine, since the remote server is fetching the profile URL. As an aside, if I simply search for my server within a Mastodon server’s interface, for example, it works fine 100% of the time. So I don’t feel like there’s something fundamentally wrong. Just this very specific remote follow prompt flow.

{
"aliases": [
  "https://ap-test.owncast.tv/federation/user/testing"
],
"subject": "acct:testing@ap-test.owncast.tv",
"links": [
  {
    "rel": "self",
    "type": "application/activity+json",
    "href": "https://ap-test.owncast.tv/federation/user/testing"
  },
  {
    "rel": "http://webfinger.net/rel/profile-page",
    "type": "text/html",
    "href": "https://ap-test.owncast.tv/federation/user/testing"
  }
 ]
}

Have you compared your request flow to what Mastodon does to another instance?

I see a GET of /authorize_interaction?url= followed by the url-encoded https://example.com/users/username and a bunch of headers you may want to compare.

Your webfinger response lacks the very entry that is required for remote follow to work. This one specifically:

    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://friends.grishka.me/activitypub/externalInteraction?uri={uri}"
    }

If I’m not mistaken "http://ostatus.org/schema/1.0/subscribe" is required if I want users on my server to support following a remote server, a flow I’m not looking to support at this time. In this case I want a remote server to follow my server (the opposite). Example: A remote mastodon user to follow the account on my server. Please let me know if I’m wrong and this entity is required the other direction as well, though I don’t know in my case what I would do if somebody landed there (I don’t have “users”), but I can deal with that if needed.

Please see the above gif example, as I believe I’m having a hard time concretely explaining the exact flow I’m talking about since “remote follow” doesn’t imply a direction.

To clarify:

I’m redirecting successfully to Mastodon via:
https://{instance}/authorize_interaction?uri=https://ap-test.owncast.tv/federation/user/testing

And it returns:

Unfortunately, there was an error looking up the remote account

Even though it looks up the account fine if you type it in the search bar:
image

Friendica via:
https://{instance}/follow?url=https://ap-test.owncast.tv/federation/user/testing

And it returns:

The network type couldn’t be detected. Contact can’t be added.

Friendica is also able to look up this account successfully via search:
image

Pleroma via:
https://{instance}/ostatus_subscribe?acct=https://ap-test.owncast.tv/federation/user/testing

And it returns:

Error fetching user.

Well. You have to use this entry either way.

When you want to follow someone using an account on your instance, you need to have this in your webfinger response so the remote server knows where to redirect after you enter username@your.instance.

When you want the opposite side of this flow (i.e. allow mastodon users to remotely interact with something hosted on your instance), you need to ask the user for their username@domain, do a webfinger request and look for that entry, then replace {uri} with the ID of the object to be interacted with and redirect the user to the resulting URL.

You definitely shouldn’t be hardcoding these URL templates.

You definitely shouldn’t be hardcoding these URL templates.

I’m not, I’m just trying to clarify what I’m seeing in the examples to try to be clear what is happening. I’m using Webfinger.

so the remote server knows where to redirect after you enter username@your.instance .

This is where I’m confused. The remote server isn’t doing the redirection, my server is doing the redirection to the remote server for them to authorize the follow.

i think @gabek is right that the subscribe property doesn’t make sense for the flow they’re looking to implement, my guess is that there’s something else wrong with the server actor but i could also imagine that some implementations are requiring that property for symmetry reasons on accident.

@gabek, this is because you’re returning an application/json content-type header, instead of the more specific application/activity+json or application/ld+json; profile="https://www.w3.org/ns/activitystreams" content type. That means that when Mastodon goes to look up the URL it can’t figure out whether it’s an actor or a status.

2 Likes