Search code examples
mastodonactivity-streamsactivitypub

Activitypub & Mastodon, how to get an Actor?


The question

I'm currently trying to implement ActivityPub on my server to make it interoperate with mastodon. I got stuck trying to retrieve an actor from another mastodon instance. The actor contains things like the inbox, outbox, and the public key for verifying requests signed by the actor.

It seams to get an actor, I need to send a signed get request. Although I know how to sign a request, I have a chicken egg problem, because the json-ld document representing the actor would contain the public key for verifying a request from that actor. Therefore, if I was to sign the request with my key, then the instance whose actor I'm trying to retrieve, in order to verify the key, would also have to retrieve my public key, and thus my actor. But if it did that, and I also check the signature, then I'd need to get that actor I tried to access in the first place to get the public key of it to do so.

How do I resolve this chicken egg situation? And why does mastodon not run into the same issue, do they do something differently?

What I tried so far

I've made an account on some existing mastodon instance. I can look up the URL for the actor using webfinger:

curl https://awoo.space/.well-known/webfinger?resource=acct:[email protected] | jq
{
  "subject": "acct:[email protected]",
  "aliases": [
    "https://awoo.space/@DPA",
    "https://awoo.space/users/DPA"
  ],
  "links": [
    {
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html",
      "href": "https://awoo.space/@DPA"
    },
    {
      "rel": "self",
      "type": "application/activity+json",
      "href": "https://awoo.space/users/DPA"
    },
    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://awoo.space/authorize_interaction?uri={uri}"
    }
  ]
}

So for that account, the actor url is https://awoo.space/users/DPA. But if I try to get the actor object:

curl -H 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"' https://awoo.space/users/DPA

I get an error: 401, Request not signed.

To be honest, I do not understand why that request needs to be signed. It didn't seam to be the case for examples I found online, but in this case, for some reason it wants a signature, and I want to handle that properly.


Solution

  • This is an odd, somewhat well-known ActivityPub quirk that's somehow a problem in theory but not in practice. The short answer is, sign your outbound AP requests with an actor from your own instance, any actor, and the remote instance will generally accept those signatures and respond happily, even if it hasn't seen your signing actor beforehand.

    (I've had conversations in AP venues about this before, but I couldn't find them on https://socialhub.activitypub.rocks/ to cite, they may have been in chat instead.)

    I suspect many AP implementations handle this with a TOFU under the covers. Ie if a remote instance gets a GET signed by an unknown actor, it fetches that actor and only then starts verifying its signatures. This may happen synchronously on the first request (and block it), or in the background.

    Also @Daniel Albrecht is right, this generally only matters with Mastodon (and some other) instances running in secure mode.