Adding federation support to Discourse


Pavilion is finalising a specification for an MVP ActivityPub plugin for Discourse (the software this community is using). The plugin is being commissioned by CDCK, the company who makes the software. Any comments on the specification in the topic on Discourse Meta would be welcome.

Please leave your feedback on Meta as I may miss them here.


Hurray :tada: fabulous news :smiley: worthy of a toot:


That will be awesome!

1 Like

Just to let you all know the first version of the ActivityPub Plugin for Discourse has been published. Happy to hear any feedback, either feature-wise or technical, on the plugin topic on the plugin’s topic


Nice work! Is this implementation based on FEP-1b12?

1 Like


The best way to think about the implementation is that it can support FEP-1b12 (aka the Lemmy implementation). The first version aims at an integration with Mastodon, so it doesn’t look like FEP-1b12. But that will be quite doable in later versions.

To get a sense of what I mean by that here’s a simple data flow model for the plugin

The AP interface is an abstracted ruby interface for ActivityPub modelled on the AP spec itself and using AP terminology. It could be packaged as a gem at some point to make it easier to integrate AP into rack projects. The simplest way to think about the current implementation is in the capability definitions for the Actor models in the AP class, i.e.


def can_belong_to

def can_perform_activity
    accept: [:follow],
    reject: [:follow],
    create: [:note],
    delete: [:note]


def can_belong_to

def can_perform_activity
   follow: [:group],
   undo: [:follow]

The AP class then interacts with an abstracted data model in the plugin, i.e. “DAP Models”. That data model essentially supports any type of relationship(s) between Actors, Objects and Activities. The DAP models are then integrated with the Discourse models.

I’m giving you some context here to demonstrate that while the simplest possible integration with Mastodon was the first goal, it was designed in such a way (i.e. with sufficient separation of concerns) to make it relatively straightforward to extend the implementation to support FEP-1b12 or other interpretations of the ActivityPub spec.


This is a general call out to folks in this community. If you want to share your thoughts on the direction and shape Phase 2 of the development of the Discourse ActivityPub plugin should take please do so now. We’ll be settling on a phase 2 specification soon so now’s your chance. We won’t necessarily be able to do everything of course but we’re open to reasonable suggestions.

You can check out what the plugin currently does in the description here

If you’re curious what the “Phase 1” spec was please see here

And you can check out the code here

cc @how


It would be good to dedicate some time to improving interoperability. The bug tracker appears to be closed, so I’ll write here.

When I tried to fetch a post from SocialHub, server returned 406 Not Acceptable. If I read the code correctly, only JSON-LD and ActivityStreams content types are allowed. But ActivityPub software must set Accept: application/ld+json; profile="" header when retrieving objects.

Attempt to fetch an actor (with a signed request) leads to 500 Internal Server Error.


My top features would be:

  1. Enable public postings — so that the Fediverse can boost announcements
  2. Enable full posting of Notes within [note][/note] up to 500 chars
    1. Maybe add a character counter in the composer (but we can count ourselves)
  3. Enable federated categories in the sense that a Discourse instance could follow another Discourse instance’s federated category, and users in both forums could discuss.
  4. Stage Fediverse users


Public postings

Once the main posting feature is a bit more stable, it would be useful for the public to boost posts. E.g., in our use case, the posts are new Fediverse Enhancement Proposals, therefore it would be awesome to have a place to advertise them to the Fediverse and hold a conversation there.

Full posting of [note]

Currently the parser cuts too early, and ignores the [note][/note] tags. Since we take time to think about what goes inside the tags, it would be better if the parser would account for good human judgement :wink:

Federated Categories

Bidirectional topics across Discourse instances would certainly mark a milestone in Discourse federation. Although @CodingHorror does not see any use for such a feature, I certainly can, in the sense that many free software communities adopted Discourse for their own usage, and cross-project discussion would add to the power of Discourse forums. See below for the trust issue :slight_smile:

Staged Fediverse Users

When a new user sends an email, it is staged: its account may become a full user account, but in the meantime, it can just participate in the ongoing discussion where it was invited.

The same can be done with Fediverse users: there’s no reason why a Fediverse account could not be staged and follow the trust levels limitations.

Moreover, when a Fediverse account is associated with a Discourse account, the reputation of that account could follow it and transmit the trust… This may open a Pandora box, but within a federation of Discourse instances, it could as well help moderation (against abusive users, and also to facilitate good behavior). This feature alone should de discussed and thought about, as two communities might not give the same credit to the same people. But the bidirectional federated topics would certainly help figuring things out. I would keep that for phase 3 or 4.

Another aspect of staged federated users would be that a person posting from a Mastodon or Pixelfed could then become a Discourse user — i.e., we could have another way of authentication via Fediverse.


Couldn’t have phrased it better. Esp. Federated Categories would be huge! Bringing fragmented, dispersed forum installations together will help the activity of the individual communities that use them. It will help boost (collective + individual) community health.

The SocialHub is like a co-shared community. We offer software projects the opportunity to have a sub-category under #software. Yet for any software project listed, this adds yet another additional channel. One more place to manage and distribute content to, an extra burden to remember to publish here. These software projects have their own channels, and SocialHub is seen as external. There isn’t much incentive to publish here, even though it is beneficial to do so, as that helps evolve the ecosystem that the projects rely on.


Thanks for the feedback guys, very valuable. I’ll let you know when we settle on a phase 2 spec.


Hey guys, this is our Phase 2 spec, which is already being worked on

  • Support editing Note post-publication

  • Support restoring Notes

  • Support publishing posts publicly as well as followers only

    • Category-level setting
    • See further Audience Targeting and Mastodon’s docs on to/cc
    • Switch to public posts as the default
  • Support accepting Activities in reply to a Note made on remotes and publishing Activities in reply to a Note made in Discourse.

    • Publish Activities concerning replies made on Discourse

      • Allow Discourse users to be Actors
      • Create Note objects for Discourse replies (posts)
      • Publish associated Create/Delete/Update/Undo Activities for their equivalent Discourse actions
    • Accept Activities concerning replies made on remotes

      • Stage the Actors of Activities from remote servers as Discourse users
      • Create Discourse replies (posts) from Note objects
      • Convert associated Create/Delete/Update/Undo Activities into their equivalent Discourse actions
    • Add a category setting to toggle between First Post only (current) and “Full Topic” which supports reply Activities.

  • Support use of Article instead of Note as the Object for a post.

    • Category level setting
  • Support Like Activity

  • Improve Note content parsing

    • Handle special characters (perhaps use a different parser). See further.
  • Support Discourse users verifying their identity on Mastodon so Discourse posts created from their Toots are associated with their Discourse user account.

    • Allow a user to perform the Mastodon OAuth Authorization flow with the Mastodon server where their account is stored. This is initiated from the user’s Discourse account settings.
    • Using the Discourse user’s Mastodon access token, obtain and store the AP ID of their Mastodon account and store it with their Discourse account.
    • Associate all Discourse activities associated with AP Activities from an Actor bearing a Discourse user’s AP ID with that Discourse user, whether they were performed before or after the user verified their identity.

Full-topic federation available at Fediverse Futures

I want to mention that our Fediverse account ( now supports replies from the Fediverse! We have not tested it yet so here is a starter…

Associate your Fediverse account to your SocialHub account

  1. Navigate to your ActivityPub preferences:
  2. Enter the domain name of your Fediverse account: the plugin will image your account there and start the OAuth dance to access your account read-only.
  3. Now your activities from your Fediverse account will be associated with your SocialHub user!

That means replies you make to the Fediverse Futures topics you catch from the Fediverse will appear as you on the SocialHub topic… This is tremendously exciting because it opens Fediverse Enhancement Proposals discussions to the Fediverse (provided you have an associated account on the SocialHub as well. Let’s test first with Fediverse Futures

  • Webfinger works and resolves to
  • Actor endpoint requires signed request.
  • When I do a signed request, the server responds with 500 Internal Error (after trying to fetch the signer’s profile) :person_shrugging:

Could you share an example of a request that returns an error?

I can’t share the exact request, but it’s a signed version of this one:

curl -H 'Accept: application/ld+json; profile=""'

The actor which signs the request:

How are you signing the request?

I think the signature code is there:

1 Like

@angus Signature header:

keyId="",algorithm="rsa-sha256",headers="(request-target) host date",signature="f/4ActgTzoolFSOiQl1yW72N+l6baacU3phMLSbXVv2W+r1XmWWfjqmZmfME3hCrCkGhfaMYaTve5mTWqqrbJEFZfqn7Mn+s3F2GP3xY/4v9ji3fmdgWts/azC0RtYKOB91XHhS2hhht1As30FDaEeJu8mbo8aUoKDOdxrVeZrmHOA2w1WDUMgz+fhDOV5H1+ZsIEBkUJKP5FICP0iwt1xLd5slUVfTa8J8ZGxmUtEo04V3X7z27k9ShQyJjZejRzryTF2T3CeWi33zVN6OJdjBM6PEbTolKdlJjBIZ6asudOGUVWOph5QD5audSdoKpkNqwLL+KwhrA4vxY8Y8/Qg=="

Host header:
Date header: Sun, 01 Oct 2023 16:47:47 GMT

The signature is generated using the private key corresponding to the public RSA key indicated by publicKey.publicKeyPem property of the aforementioned actor.

1 Like

@silverpill Thanks. @how Can you share the error from the logs as well?