Evaluating permissioned spaces for community contexts

@dholms.at dropped the 4th of the Permissioned Data Diary blog posts a bit before Atmosphere Conf last month. @zicklag.dev and I only got around to looking at it in more detail this week.

For context, we are working on @roomy.space, which has fairly complex needs in terms of both private data and group management. As we've worked on our own interim 'Leaf' solution for this over the last year, we've spent a lot of time thinking about how systems might be able to provide similar guarantees to communities as users get with ATProto currently, and what happens when the two intersect.

Since getting a feel for the design sketched out in Diary 4 we've been looking at how we might be able to create a generic service for managing community spaces we're currently calling an arbiter - both a 'space host' and a 'managing app', adding certain common app-level logic around managing community member lists, including an RBAC layer. Working on a design for that this week has helped us dig into the proposed approach for permissioned spaces including finding some minor points of confusion or concern, mostly around the proposed space identity/addressing scheme.

Some assumptions:

If you write data to a permissioned space, you are consenting to the space owner arbitrarily changing who can read that data

When you post into a bucket, your post inherits the ACL of that bucket. When someone is added to a bucket, they get access to everything in it. When they’re removed, they lose it. ( Diary 2 )

Therefore the space owner may have some ethical responsibilities toward any users writing data in the space

If communities are contributing data to a permissioned space, those users may expect that power to control read access is accountable and governable in some sense

The space primitive places all authority to mutate the ACL with the space owner, so a 'managing app' is required to provide this kind of accountability/governance layer

If the space is addressed by space-owner-did/space-type-nsid/skey, this is the permanent identity for that space, and this ownership/root authority to mutate the ACL is not transferable

Transfer of ownership from individual to community

TL:DR; what should users who inadvertently become community managers do if ownership of some spaces is not transferable?

For personal data, the space owner is simply the user's own DID. For shared spaces like communities, a dedicated space DID is preferable. A dedicated DID allows ownership to be transferred by updating the DID document without breaking any existing references into the space. (Diary 4)

Maybe 'allows ownership to be transferred' is slightly confusing wording here? The space owner's DID is part of the permanent identifier for a space - I'm assuming that what's meant here is that hosting of the space can be transferred between providers, including potentially adversarial migration the same way a PDS repo can be migrated, by holding a rotation key with higher authority than the host holds.

This solution works for us, but the user's own DID being the owner is a bit of a concern. In short - how sure can we be that read access to other users' data in a user's 'personal space' will always be only the personal concern of the user who owns the space?

What happens when an individual user creates a space that starts small and is mainly focused around that user's content, but as time goes on and the user list grows and starts to become more of a community-scale resource?

For example, say Alice is the creator of a small indie game and creates a private forum for users to discuss it, thinking at the time that it's just a fun project. Two years later, the game has become very popular, is now maintained by a 10-person team and the forum has 10,000 users, but every time someone wants to join, this has to go through Alice's PDS. She wants to quit the project and leave her teammates in control of the forum.

In its role as a space host, our 'arbiter' service would need at least a signing key for the space owner DID. Maybe Alice could delegate this authority to the community manager service by asking it to create a keypair and adding the public key to the verification methods in her DID document, but the root authority will be permanently tied to her account.

Changing space types/modalities

Similar to the above concern, noting that space type NSID (and skey) are also part of the address for a space.

This type is defined by a published lexicon and serves as the OAuth consent boundary. When a user logs into an application, they grant access based on the type of space. For example: app.bsky.group, com.atmoboards.forum, app.bsky.personal.

Say that Alice creates a forum on one app. A year later she decides she wants to try a different app to connect with this community, say, like Roomy, which supports forum modalities as well as realtime chat. If the space is configured to default-deny new apps, then as the space owner she controls whether another app has read access to all the different users' data in a space. Each user can then give individual consent for the app to write to certain collections in their repo in that space. Say that within three months, all of the users migrate to the new app, and the modality changes.

What are the practical implications of the space being permanently tied to the space NSID on the first app? My main thought is that though in the majority of cases the NSID may be a good consent boundary, there may be cases where we want to get more granular, and then other cases where it would be more convenient to change the NSID and having to use granular methods gets annoying. These may of course be fairly exceptional.

Migrating between spaces, multi-space records

With both the space owner and space type NSID being fixed for any given space, we can envision some communities wanting to migrate from one space to another. This is essentially a very high-coordination process - comparable to restoring a PDS backup to a new account after losing control of the DID, with all internal and inbound links broken in the process, but with the added condition that every member needs to be independently involved in the migration.

We’re currently arguing about what should be considered the authority of the URI. The user DID because the record is hosted by the user and authority for the record ultimately rests with the user? Or the space owner DID because it authorizes a user’s ability to create a record in the space in the first place? (Diary 4)

This may be an argument for user's records keep the user as authority, to keep referential integrity across multiple spaces. From my view of the proposed design, the space owner doesn't have much capacity to enforce write authorisation (e.g. in the next section, "Write enforcement is ultimately handled by readers of the space"), and if a space owner removes a user from a space, that users' records should certainly not be deleted from their own PDS.

Moreover, users may want to be able to reference the same record across multiple different permissioned spaces, without having to copy it across every time. Apps will of course need to handle the situation where they cannot hydrate the records because that particular app hasn't been authorised, and there are pros and cons for different approaches here, but given that cryptographic integrity guarantees of records is becoming increasingly taken advantage of in different Atmosphere apps, there's something to be said for users having a set of their own records that are first private for them only, and selectively or in bundles shared to various spaces.

This scenario where record addresses and CIDs are independent from the spaces it is shared in could significantly lower the stakes for space migration.

Some other questions

There's a few things that would feel helpful for us to have a better feel for as we're exploring future architectures for Roomy:

Are ACLs intended to be public? As in, can anyone access the member list? Or you can only access it if you're in the space, or perhaps all you can access is whether you are in the space or not?

Could public read access for permissioned spaces be on the cards? We like the semantics around write notifications/scoped backfill as compared to the escalating ingress load of full firehose subscription and backfill that several apps are seeing lately and could see this being a useful pattern. There's also something nice for the user of being able to easily switch a set of records between public and private, like a user can do with their Instagram profile, for instance.

It seems that with the ACL being a tuple of (UserDid, Read | Write), and write authorisation enforcement only happening at the app level, the latter part is really just informational metadata for apps. Could this be expanded to something more generic - perhaps a lexicon that accompanies the space type NSID? This could make it easier to implement more fine-grained permissions within the one space.

Thanks for reading! We will try to publish more soon about our ideas for an 'arbiter' with a generic RBAC layer on top of permissioned spaces, and hopefully other useful community governance primitives.