Sessions and sharing
A site session binds one viewer, one host, one site descriptor, and the connector selected when the session opens. It gives the broker a relay base path and a place to record sharing decisions and lifecycle state. It is not automatically an authorization credential merely because its ID is difficult to guess.
Opening a session is a product policy decision
The lifecycle service resolves the current site, requires it to be available, and asks ISiteSharingPolicy whether the viewer may open it. Every allowed or denied decision records the site, host, viewer, policy name, reason, details, evaluation time, and the session ID when one was created.
The supplied metadata policy allows:
- the same effective user as the host;
- a user in
allowed_viewer_user_idswhensharing_modeisexplicit_allowlist; - any valid effective user when
sharing_modeisallow_all.
Without one of those conditions, access is host-only. The HTTP open route uses the identity from the optional authentication dependency when present and rejects a conflicting body identity. When no authenticated identity is available, the body must provide a valid effective user ID.
This policy is a reference implementation. Organization membership, tenant boundaries, invitations, approval, purpose, and expiry belong in an application implementation of ISiteSharingPolicy, not scattered among route handlers.
Protect the complete route family
The reusable router does not consistently apply identity to every session operation. Supplying its required and optional authentication dependencies protects authenticated list operations and registration, but does not by itself close the whole boundary.
| Operation | Supplied router behavior | Application requirement |
|---|---|---|
| list sites or read one descriptor | anonymous | protect or redact if discovery is not public |
| list sessions or access decisions | required identity; results limited to host or viewer | keep the dependency authoritative |
| open a session | optional identity; otherwise body identity | require authenticated identity for untrusted use |
| read one session | no identity check | require host/viewer or an explicit capability policy |
| close or revoke | no identity check | define which participant or operator may mutate lifecycle |
| relay HTTP | no identity check | bind every request to the authorized viewer/session |
| subscribe to events or invoke actions | optional identity; absence is accepted | require identity or a deliberate signed-capability design |
Apply one outer middleware or guarded-router policy that covers all of these routes. If the product intentionally uses a signed session URL as a capability, define its scope, expiry, revocation, leakage protections, and tests. Do not let an absent optional dependency make that decision by accident.
Connector registration requires an authenticated host. Remote unregistration additionally checks that host against the stored owner and checks the connector client ID. That protection is current; it does not compensate for the separate session-route gaps above.
Session states are explicit but not automatic
Normal creation goes directly to active. close_session() changes the session to closed, and revoke_session() changes it to revoked; both release the in-process loopback client's resources. Later relay, event, and action operations reject an inactive session.
The model also names pending and expired, but the supplied runtime has no time-based expiry, idle timeout, or cleanup scheduler. Closing a session is not the same as proving that a prior local effect stopped or was undone. A product needing expiry must own the clock, transition, resource release, and user experience.
Default state is process-local
The initialized runtime uses in-memory stores for descriptors, sessions, and access decisions, plus an in-memory event bus. A restart forgets them, and several application replicas do not share them. The access-decision store keeps its newest 200 records by default.
That shape is appropriate for focused development, an embedded application, or a one-process deployment whose limits are understood. A durable or horizontally scaled product needs shared implementations and a cleanup policy. The runtime constructor currently creates its concrete in-memory stores directly; replacing them requires deliberate lower-level composition or an extension of the runtime helper rather than a configuration flag.
Align browser credentials with the policy
CooperativeSiteBrowserClient uses native EventSource for events and ordinary fetch for actions. It has no built-in bearer-header callback. Ambient same-site cookies, an authenticated same-origin shell, or a deliberately signed URL can fit; a header-only bearer design needs a different SSE transport or wrapper.
Choose the browser credential path together with the server authorization matrix. A strong server dependency does not help if the browser client cannot present its proof on every relevant request.
Next: Events and actions.