Architecture Decision Record

0046. External collaboration — the guest model

Context

ADR-0012 left cross-tenant sharing [OPEN], and the design review named it the largest workforce-parity hole: Entra B2B — invite an outside collaborator into your tenant, govern what they may touch, review and expire their access — is table stakes for the workforce product, and it presses directly on the constitution: rule 3 forbids cross-tenant strong reads on any hot path, so "a principal from tenant A acting in tenant B" must not become a cross-tenant dependency. This record closes the [OPEN] with a model that keeps every tenant's decisions local. It is the identity-model decision; the product surfaces (invitation UX, guest views) layer on it as proposals.

Decision

  1. A guest is a local principal with a home reference — never a foreign read. Inviting an external collaborator creates an ordinary principal in the inviting realm (ADR-0011: immutable local id, realm-scoped uniqueness, its own data key per ADR-0034) of subject type guest, carrying an immutable, informational home reference (the home realm/tenant for a Vord-homed guest, or an external issuer + subject once federation exists). Every decision about the guest — authorization, tokens, revocation, erasure — is a local decision over the local principal: rule 3 holds because the home link is data, not a dependency. The same human in three tenants is three principals with three lifecycles, which is the correct shape: each tenant governs its own grant, and no tenant's availability or policy reaches into another's hot path.

  2. Invitation → redemption is a two-phase ceremony, local-credential first. An invitation (issued by an authorized admin or delegated owner — proposal 0016) creates the guest principal in an invited state and sends a redemption link (notification delivery, proposal 0011). Redemption binds a credential and activates the principal. Stage one — now, no federation dependency: redemption verifies the invited contact (the proposal 0003 mechanics) and enrolls a local credential (passkey preferred, ADR-0020). Stage two — when upstream federation lands (ADR-0019, M7): redemption may instead bind the guest to their home credential, so they sign in with their home account and the inviting realm receives an ordinary federated login mapped to the local guest principal. The model is identical in both stages; only the credential binding differs — which is what lets guests ship before federation does.

  3. Guest is a first-class subject type in authorization. Relations (ADR-0006) distinguish guest principals, so realm policy can state constraints the engine enforces: "guests never hold relation X", guest-forbidden scopes, guest-visible resource subsets — the SoD-constraint machinery of ADR-0030 applied to externality. Per-realm external collaboration policy governs who may invite, which domains may be invited (allow/deny lists), and what may be granted.

  4. Guest lifecycle is governance-first-class, with expiry as the default. Two maturities, staged honestly: dormancy expiry — an unused guest account expires into a disabled state rather than lingering — is a simple realm-policy timer and ships with the guest ceremonies (M4–M5); access reviews — recurring certification of guest grants — are ADR-0030's campaign machinery and arrive when IGA productizes (Step 3), applying to guests like any principal. Deprovisioning joins the revocation path exactly as SCIM deprovisioning does (ADR-0018's pattern: directory write + event in one commit, tokens die within the freshness budget). Erasure requests against a guest principal are local (ADR-0034) and never reach the home realm.

  5. Guest tokens are ordinary local tokens. sub is the local guest principal id; guest-ness and the home reference surface as directory attributes mappable into claims through claims customization (proposal 0008) under its normal rules — no new token-format seat, no special verifier behavior. Relying parties that must treat guests differently read a claim; Vör verifies nothing differently.

Consequences

  • The workforce collaboration story exists without a single cross-tenant read: invitation, sign-in, authorization, revocation, review, and erasure are all tenant-local operations — rule 3 is preserved by the data model, not by discipline.
  • Duplicate identity is accepted and owned: linking the same human across tenants is deliberately not modeled (each grant is sovereign); if a future "my organizations" convenience is wanted, it is a home-realm feature over the guest's own references, never a cross-tenant join.
  • Stage-one guests (local credential) mean B2B collaboration ships at the multi-tenant milestone rather than waiting for federation; stage two upgrades sign-in convenience without a model change.
  • Guest principals count against the inviting tenant's quotas and write rate (ADR-0012), and invitations are an abuse surface — invitation issuance joins the rate-limit umbrella (proposal 0006) and attack-protection signals (proposal 0021).
  • Resolves ADR-0012's cross-tenant [OPEN]; refines ADR-0011 (subject type), ADR-0030 (guest reviews), and composes with proposals 0015/0016 (org-scoped guests and delegated invitation are the org-level application of this model).

Build-order note

The guest subject type and home-reference field are directory-schema facts that must exist when the schema stamps at M4; the invitation/redemption ceremonies and collaboration policy attach at M4–M5 (stage one), and the home-credential binding upgrades at M7 with ADR-0019.