diff --git a/proposal.md b/proposal.md index c9ab27b..2545d6d 100644 --- a/proposal.md +++ b/proposal.md @@ -2,14 +2,24 @@ This document specifies the proposed `opensocial.group` model. See the [project README](README.md) for an overview, background, and design posture. -An **atmospheric group** is a DID with a bunch of permissioned spaces under it. +An **atmospheric group** is a DID with a bunch of permissioned spaces under it. There is a one-to-one mapping between groups and DIDs. `opensocial.group` is a set of **lexicons** describing **space types, record types, and methods** for modeling and interacting with atmospheric groups. -Groups run on `opensocial.group`-compliant space hosts. These are servers that natively understand the standardized records & methods. Groups should be able to migrate from one space host to another. +Groups run on `opensocial.group`-compliant **group hosts**. Groups should be able to migrate from one group host to another without disrupting how members interact with the group. `opensocial.group` is a *peer* of the [simplespace implementation](https://github.com/bluesky-social/proposals/tree/main/0016-permissioned-data#required-pds-space-management-simplespace), which PDSes are required to implement. It is not expected to operate on most PDSes and does not layer on top of simplespaces. +## Group hosts + +A **group host** functions like a PDS for group accounts. Just as a person's PDS hosts their account and data, a group host manages the group's network identity, hosts and signs its public repository and space repositories, and acts as the space host for the group's spaces. + +It adds the group-specific functionality needed to manage a collectively controlled account. It understands the `opensocial.group` records and methods, enforces space access policies, and checks roles when authorizing group-account OAuth scopes. It is both the authorization service and the repo host for records authored by the group. + +Members continue to publish their own records to their own PDSes, including records in the group's spaces. Members' repositories *are not* stored on the group host. + +The group host serves as the OAuth authorization server for the group account. Users authenticate to it using their personal atproto accounts, and the host determines which group-account scopes they may authorize from their roles. This is described in the [OAuth flow](#writing-as-the-group-did) below. A user's account may be on a different PDS, and that PDS only needs to support the standard atproto OAuth flow for authenticating them. + ## The spaces There are two `opensocial.group` spaces: @@ -29,25 +39,33 @@ There are no deny rules or caveats. So authorization composes simply by **unioni Membership is defined **bidirectionally**. The group creates a `membership` record in the `members` space and the member in turn creates an `acceptance` record in the same space. +The group DID itself is implicitly a member with all group permissions. It does not need its own `membership` or `acceptance` records or assigned roles. + Two actions — **assigning** a role to a member and **ejecting** a member — are parameterized by the roles that they apply to. Roles may entail certain conventions. For instance, the Bluesky app will likely special-case the roles `admin` and `moderator` and give special UI affordances/badges to accounts with those roles in a group. Other roles may be treated as flair or metadata. A group is free to ignore the convention. -Each space in the group (both modality-specific spaces & `opensocial.group` spaces) has an open social `access` record. This record specifies which roles are able to view the space. Read access is enforced by the space host. +Each space in the group (both modality-specific spaces & `opensocial.group` spaces) has an `access` record. This record specifies which roles are able to view the space and which group-account OAuth scopes each role may authorize. Read access is enforced by the space host. -All other types of access are considered **modality-specific** and as such are **app features.** Who can write to a space, who can pin a thread, who can post to an announcements channel, who can create an event, etc. Each of these is declared in the modality’s **own lexicon** within the relevant space. However, these authorization declarations may still make use of the group-defined roles. +Permissions for modality-specific actions are **app features**. Who can write to a space, who can pin a thread, who can post to an announcements channel, who can create an event, etc. Each of these is declared in the modality’s **own lexicon** within the relevant space. These authorization declarations may use the group-defined roles. ## Writing as the Group DID Certain modality-specific records need to be created *by the group DID*. For instance, pinning a post at the top of a forum may require a `pin` record created by the group DID in the forum space. -If a user (for instance, a group admin) wishes to write as the group DID, they do so by holding an OAuth credential for the group DID and writing that record to the group service. The group service will support all `com.atproto.space.*` CRUD methods. +An application writes these records using an OAuth session for the group DID. The group host supports the `com.atproto.space.*` CRUD methods. Group management methods also accept group-DID OAuth sessions. + +Authorization uses a two-sided OAuth flow: -This does not imply that the user needs to have “full access” to the group account or that they need to log in to the app as the group account in a traditional sense. Rather, the group service also serves as an OAuth authorization server for the group DID. Instead of requiring a password, it requires that the user authenticate using their personal account. +1. The application starts an atproto OAuth flow for the group DID, requesting the scopes it needs. +2. The group host authenticates the user by acting as an OAuth client to their personal PDS in a second flow. +3. The group host checks the user's roles and presents consent for the allowed scopes, as specified in the relevant `access` records. +4. On approval, the application receives an OAuth session for the group DID. -The OAuth scopes that each user/role is able to request for the group DID are also encoded in the `access` record in each relevant space. +Applications can use these sessions in two ways: -Applications are in charge of juggling these credentials. They may choose to offer an “account switcher” where an admin switches to using the group account, or they may do this more transparently and just use the group account credential when the admin performs some action that requires it. +- **Per-user sessions.** Each user authorizes a session for their own actions, using the scopes allowed by their roles. This suits personal tools and independent clients. +- **Shared application sessions.** An admin authorizes a session that the application uses on behalf of multiple members. This avoids a separate group authorization flow for each member when many members use the same trusted application. The application is responsible for checking each member's permissions before using the group session on their behalf. ## Presence & Discoverability