
ActivityPub: Client to Server endpoint discovery
I’ve re-started building with ActivityPub’s #c2s API based app. So this post is to document some of the challenges and hiccups.
- The very first thing a user will want to do is login, right? So, we ask the user for their instance URL or their handle (webfinger: user@domain.tld).
- Our app then needs to find an info about how to connect to the site.
Luckily, the OAuth 2.0 standard exists! In our case we would be looking to RFC 8414: OAuth 2.0 Authorization Server Metadata. The main point is that once we have a server URL, we can look up the configuration routes via a predictable URL
/.well-known/oauth-authorization-server
If this route doesn’t exist then we have some alternatives. We could look for the instance actor.
Depending on implementation, we might find this via
nodeinfo
(FEP-2677), or we might find it viawebfinger
(FEP-d556).- The nodeinfo route is the more convoluted one, because fetching
example.social/.well-known/nodeinfo
we potentially receive a payload with links to version 2.0, and or 2.1.example.social/nodeinfo/2.1
.This would lead us to parsing nodeinfo’s
metada
ta field, looking forstaffAccounts
which would be an array, let’s just take the first one. - The webfinger route would be:
example.social/.well-known/webfinger?resource=https://example.social
From there we parse the webfinger links field which is an array, looking for an object whose has
rel
=”self
” and whosetype="application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
.Whew, this object’s
href
value leads us to the instance actor. - Finally, we arrive at an actor profile, where we will look for the endpoints field, and hope to find*:
oauthRegistrationEndpoin
toauthAuthorizationEndpoint
oauthTokenEndpoint
- *However here too the road can be fraught with dangers… a number of servers are not allowing CORS requests on actor profiles.
If implementations aren’t serving an oauth discovery endpoint RFC8414, and are limiting requests to actor pages, then there is really not much we can do!
- The nodeinfo route is the more convoluted one, because fetching