Subscribe and unsubscribe to a community (Follow)

Welcome to the inaugural post in a series about things I’ve discovered about how ActivityPub works in the real world, beyond what the spec says.

While the spec is pretty good and easy enough to understand there is a lot left undefined so implementations have filled in the blanks in their own ways. I hope to shed some light on these as I build PieFed and bash my head against all those rough edges so you don’t have to.

Very recently I’ve made it possible for PieFed to follow communities on other instances and for people using other instances to follow communities on the local instance, so that’s what I’ll cover in this post.

But first, a quick diversion:

In Mastodon, every user has their own ‘Inbox’ where content for them gets sent to. However in the ‘threadverse’ (a subset of the fediverse which includes lemmy, kbin, piefed) the content is for everyone to read so most of the AP communication happens using shared inboxes. This means there is a single URL on each server where all the data gets POSTed to. If the instances have not communicated before they need to discover each other’s inbox URLs by using WebFinger, a separate protocol which I have also written about.

Let’s assume the server wanting to initiate a Follow already knows the inbox URL of the target server.

Back to the main point:

Following is quite a simple operation so all it needs to do is communicate who the user doing the follow is and which community they want to follow. For example if I user ‘rimu’ on the piefed.ngrok.app instance wants to subscribe to ‘real news’ on kglitch.social, then piefed.ngrok.app needs to send a HTTP POST to the kglitch.social shared inbox, containing this JSON:

{
"actor": "https://piefed.ngrok.app/u/rimu",
"to": [
    "https://kglitch.social/m/realnews"
],
"object": "https://kglitch.social/m/realnews",
"type": "Follow",
"id": "https://piefed.ngrok.app/activities/follow/7"
}

‘actor’ is the user. Identify them using the URL of their profile on piefed.ngrok.app. ‘to’ and ‘object’ are the URL of the Real News community.

That’s it. Well, not really because JSON-LD but that needs a separate blog post. Also every POST needs a special header to digitally sign it, which needs a separate blog post.

But wait, there’s more

Also, the Follow above it just a request to follow. The receiving server will respond with a POST of it’s own to accept the request. Normally this happens immediately as there is not yet any moderation functionality in the threadverse that would let people manually approve requests to join a community. There will be once PieFed implements it though.

Once the follow is received by the remote server, it will Accept the follow by POST-ing to the original server shared inbox something like:

{
"actor": "https://kglitch.social/m/realnews",
"to": [
    "https://piefed.ngrok.app/u/rimu"
],
"object": {
    // the follow request that is being accepted
},
"type": "Accept",
"id": "https://kglitch.social/activities/accept/asdfsdfsfds"
}

This means that the community, “Real News”, is telling rimu@piefed.ngrok.app that something (the “object”) is Accepted. In this case the object is just a copy of the original Follow that was sent to it. I commented it out for clarity, and below is the full POST including the follow:

{
"actor": "https://kglitch.social/m/realnews",
"to": [
    "https://piefed.ngrok.app/u/rimu"
],
"object": {
    "actor": "https://piefed.ngrok.app/u/rimu",
    "to": null,
    "object": "https://kglitch.social/m/realnews",
    "type": "Follow",
    "id": "https://piefed.ngrok.app/activities/follow/7"
},
"type": "Accept",
"id": "https://kglitch.social/activities/accept/asdfsdfsfds"
}

I am still unsure if the “id”s actually matter or if they’re just gibberish that can be any value and are ignored in practice. It looks like the intent is that the recipient of the Accept could check if it really did send a follow with that ID but who’s got time for that? PieFed is ignoring them for now.

Strictly speaking, an instance shouldn’t consider the Follow to be established until the Accept arrives. But as it is sent automatically by Lemmy and Kbin, it could be assumed that all follows are accepted without waiting for the confirmation. Kbin does this, which is a bit naughty.

Hypothetically, a request to follow could be Rejected, using exactly the same response JSON except “type”: “Reject” instead of “type”: “Accept”. No threadverse software uses this part of the protocol, yet.

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *