Are FEP-e3e9 (Actor-Relative URLs) and FEP-ef61 (Portable Objects) Incompatible with did:web and each other?

Let’s say I have a DID did:web:example.com and I want this DID to have multiple actors for different purposes, for example ap://did:web:example.com/1 is one of them, and 2 and so on. If I wanted actor-relative URLs for it, my actor has to have a service defined that matches one inside the DID document. Let’s say I make it in my actor object:

"service": [{
     "id": "ap://did:web:example.com/1#storage",
     "serviceEndpoint": "https://storage-provider.example"
  }]

Now if I want to put it in the DID document, I don’t think I can query because querying seems to use a fragment relative to the DID, but the ap id url doesn’t match, both because it has an ap:// and because it has its own path component /1 separate from a web:did path.

The problem seems to both be that actor relative queries right now can’t resolve a portable object URL and that a portable object URL has a path that the DID document doesn’t know about because it’s just a DID. I didn’t see anything in the DID spec that said that you had to make your service endpoints IDs match your DID, but it’s at least implied since the examples all do it that way and querying is said to be based on a DID document fragment.

The only way I can think of to solve this is to require that a DID can only have one actor, and the actor’s ID is just ap://${DID} and actor relative URLs FEP validation step 6a is modified so service IDs inside the DID document are just a DID with a #fragment, and you strip the actor service ap:// before trying to match them instead of a strict match.

halp

1 Like

From fep/fep/ef61 at main - fediverse/fep - Codeberg.org

The authority component MUST be a valid DID.

Any DID URL capabilities of a DID method MUST be ignored when working with ap:// URLs.

So it looks like FEP-ef61 has one or two requirements that make it incompatible with the other FEP for actor-relative URLs. Specifically, ef61 disallows path/query/fragment components after the DID identifier, and a “bare” DID identifier is needed? Whereas e3e9 depends on the query component in order to make use of DID parameters.

So it seems as you say.

Aside from that, I don’t think ap:// URIs are intended to be used outside of the /.well-known/apgateway endpoint? I suppose @silverpill can clarify or confirm. But it looks like you are trying to use them within a DID document.

Also:

I’m pretty sure they don’t have to match, it’s just using fragment components for convenience. So this would work too:

"service": [{
     "id": "https://storage-provider.example/didService",
     "serviceEndpoint": "https://storage-provider.example"
  }]

I’m not actually sure how that interacts with FEP-e3e9 and how to correctly format the service parameter. Maybe @codenamedmitri has some ideas? My naive assumption would be this:

?service=https://storage-provider.example/didService&relativeRef=/

Percent-encoded, of course.

1 Like

Are FEP-e3e9 (Actor-Relative URLs) and FEP-ef61 (Portable Objects) Incompatible with did:web and each other?

@Zero I have an impression that these FEPs are trying to solve the same problem, so you’re not supposed to use them together. But it is an interesting thought experiment.

FEP-ef61 doesn’t disallow these URI components. Implementers can use path, query and fragment, the only unusual requirement is that path must not be empty.
However, this capability of ‘ap’ URLs is distinct from URL capabilities of plain DIDs.

‘ap’ URLs can be used anywhere as long as they resolve to an ActivityPub object secured by FEP-8b32 proof. In theory they can also be used with other types of JSON and JSON-LD documents with embedded proofs, but this is out of scope of this FEP.

1 Like

I received evidence that service IDs don’t need to start with the DID, so they could contain ap:// URLs. I guess in AP’s circumstance, query parameters on a DID for resolution is not necessary since a simple match on the entire service ID would work.

The main problem I was trying to solve when I ran across this was different, so I will create a separate thread for that.

Correct, yeah: the two FEPs, Actor-Relative URLs and Portable Objects, are incompatible with each other (they are two different solutions for the same problem, essentially).

The Actor-Relative URL IS supposed to be compatible with did:web, that’s one of the major goals of it.

1 Like

Then what is this this requirement doing, if not disallowing DID path/query/fragment?

Any DID URL capabilities of a DID method MUST be ignored when working with ap:// URLs.

From my understanding, ap:// scheme seems to require a “bare” DID for the authority component, and then the ap:// URI appends its own path (required) and query and/or fragment (optional)

Ah, I see, you were correct. Authority component is a “bare” DID.

That being said, only paths and fragments are currently utilized. So query parameters can be used to access the underlying DID.

please use meta URIs

I spent several days reading specs on did:web and did:key and DID core. I also read up on DID documents and controller documents and how you define services. I came to the conclusion that DIDs without an arbitrary path component are a nightmare to make work with various expectations in ActivityPub, such as opaque IDs; and finally, that the ap:// URL syntax, with bare DID as its authority and its own path for resolving portable AP objects, is suitable. I decided if you really want to forward-link your AP actors inside the DID document back to the Fediverse, that you should use its ap:// URL, and if you need to refer to it via a ?service= query, to just use the entire ID, which I confirmed in DID Core as being valid.

It is not specified anywhere, but I also decided in my implementation, I will optionally forward-link my actors inside my DID document thusly:

"service": [
    {
      "id": "#actor-1",
      "type": "ActivityPubObject",
      "serviceEndpoint": "ap://did:web:example.com:user:zero/actor-1"
    },

…where the id URI points to a fragment on the DID document, and the serviceEndpoint is the ap:// path. Gateways are still as defined in FEP-ef61.

I chose this over FEP-e3e9 because DID query parameters are arbitrarily ordered and so if you wanted to assign an ID to an object by this addressing you would have to come up with a fixed order for them, and at that point it’s less complicated to use a URI path which is just an opaque string that has to be matched. And not all DIDs have an arbitrary path component, so the ap:// URL gives you one to use. I also chose it because there are two working implementations of that FEP.

1 Like

It sounds intriguing, but I couldn’t quite understand that doc.

Totally valid point! (I wonder if I can add canonical query param ordering section to that fep…)

2 Likes

it’s a proposed syntax for bolting on custom metadata to arbitrary URIs, by using more URIs.

kinda like how there’s ap://did:..., but specifically designed as an extension point. importantly, and unlike traditional ad-hoc solutions (like this ap:// thing), it lets you add metadata parameters without conflicting with the embedded URI’s own parameters. (so, if it were a meta-URI, you could add parameters to ap:, without them conflicting with the parameters on did:.)

1 Like

Wouldn’t you also need to restrict the presence of other query params? I think there might be deeper issues here…

1 Like

Wouldn’t the canonical order of the parameters simply be determined by the resolved object’s id? Otherwise I think it’s usually a mistake whenever any implementation tries parsing, normalizing, and reconstructing an id instead of treating a resolved id as the authoritative identifier (as a plain string).

3 Likes

Ahhh yeah good point.

Maybe the FEP could just state explicitly that implementations sending these URLs to have a canonical representation for their own resources since they’re still just opaque IDs to everyone else. An implementer should know this already but…haha

I said I was going with the other FEP, but have been discussing this with the work wife and and we would prefer to make your FEP work since it would just use regular DID resolution. It appears Streams may be kaput and Mitra only partially supports the other FEP so I think it’s early enough for us to do something different.

1 Like

Please make a new thread introducing it and giving examples!

1 Like

No, there is now a fork called Forte, but the old branch is still maintained. Both branches support FEP-ef61.

What if you don’t want to resolve the object just yet? Are you suggesting that there is a hard dependency on resolving an object before you can refer to it?