Skip to content

feat(auth): add server invite links - #1983

Merged
hmans merged 7 commits into
mainfrom
hmans/server-invites-design
Aug 11, 2026
Merged

feat(auth): add server invite links#1983
hmans merged 7 commits into
mainfrom
hmans/server-invites-design

Conversation

@hmans

@hmans hmans commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Why

Self-hosted servers need an operator-controlled way to restrict new account creation without making email a requirement for SSO identities. Invite links also need auditable lifecycle facts and correct use limits across multiple Chatto replicas.

What changed

  • adds static open / invite_only account admission configuration, defaulting to open
  • adds administrator-managed invite links with optional use limits and expiry, revocation, retained history, and the user.invite permission
  • records invite-link creation, redemption, and revocation in EVT, with a replayable invitation projection
  • exposes conventional https://<server>/invite/{token} links with fixed 16-character URL-safe opaque tokens
  • derives each token as a 96-bit truncated HMAC of the durable invite-link ID using a purpose-separated key rooted in core.secret_key; raw bearer tokens are not persisted
  • resolves opaque tokens through a process-local lookup derived from the EVT invitation projection and fails closed on any detected truncated-token collision
  • validates links at a GET entry point, binds only the durable ID to the signed browser session, and immediately redirects to registration so the bearer token leaves the address bar
  • atomically commits invite-link redemption with direct or SSO account creation under the whole-EVT OCC boundary
  • gates direct registration and external-provider auto-provisioning while preserving existing-account sign-in and linking
  • adds AdminInviteLinkService, the invite-link administration UI, translations, public discovery metadata, generated API clients/reference docs, operator documentation, FDR-036, ADR-070, architecture inventory updates, and glossary terminology

Compatibility, rollout, and security

  • Public protobuf changes are additive relative to main. The 16-character token format and final user.invite permission name are unreleased refinements within this feature. AccountCreationPolicy is absent on older servers and new clients treat absent or unknown values as open.
  • ProviderMetadata.auto_provision is optional; new clients treat absence from older servers as unknown/capable, while new servers explicitly describe whether a provider may create accounts.
  • Older clients cannot complete registration against an invite-only server. Operators must upgrade every serving replica before enabling invite_only, because older replicas do not enforce invite-link admission.
  • Persisted invitation events are additive. Existing RBAC policy is not rewritten; effective owners can grant user.invite, and fresh default administrators receive it.
  • Invite links are bearer capabilities. Chatto redacts /invite/* from request and internal-error logs and returns no-store, no-referrer, and noindex directives; reverse proxies and CDNs must redact the path suffix in their own access logs.
  • Rotating core.secret_key invalidates shared links while retaining durable invite-link records so administrators can copy newly derived links.

Test plan

  • invite-link model tests with -race, including deterministic 16-character derivation, secret rotation, validation, and projection-index refresh
  • mise test-cli
  • mise test-e2e — 651 passed
  • mise lint
  • mise license-check
  • docs website production build
  • Chrome DevTools verification of admin creation/copy, exact 16-character URL-safe token shape, valid invite-only redirect, one-character mutation rejection, and console output

Closes #1014.

@hmans
hmans force-pushed the hmans/server-invites-design branch from 129b6d0 to 241ccb5 Compare August 11, 2026 12:49
@hmans hmans changed the title feat(auth): add server invitations feat(auth): add server invite links Aug 11, 2026
hmans added 4 commits August 11, 2026 17:12
…design

* origin/main:
  fix(i18n): restore regional locale fallback chains (#1987)
  feat(rooms): allow flexible Unicode names (#1986)

# Conflicts:
#	apps/frontend/messages/de-AT/admin.json
#	apps/frontend/messages/de-AT/auth.json
#	apps/frontend/messages/de-AT/rbac.json
#	apps/frontend/messages/de-CH/admin.json
#	apps/frontend/messages/de-CH/auth.json
#	apps/frontend/messages/de-CH/rbac.json
@hmans
hmans merged commit ce6b525 into main Aug 11, 2026
16 checks passed
@hmans
hmans deleted the hmans/server-invites-design branch August 11, 2026 16:12
hmans added a commit that referenced this pull request Aug 11, 2026
…ideas

* origin/main:
  feat(auth): add server invite links (#1983)

# Conflicts:
#	cli/internal/pb/chatto/core/v1/event.pb.go
#	docs/fdr/INDEX.md
hmans added a commit that referenced this pull request Aug 11, 2026
…-0-details

* origin/main:
  docs(events): document integration and logging contracts (#2004)
  fix(events): guard single-run lifecycles (#2003)
  fix(events): add bounded subject reads (#2002)
  fix(events): validate snapshot bindings (#2001)
  fix(events): require pointer projections (#2000)
  fix(events): make nil loggers safe (#1999)
  ci: run pull request workflows for stack bases (#1998)
  feat(auth): add server invite links (#1983)

# Conflicts:
#	apps/frontend/src/lib/api-client-tests/viewer.spec.ts
#	cli/internal/connectapi/api_contract_test.go
#	cli/internal/core/projection_wiring.go
#	cli/internal/evtstream/publisher.go
#	cli/internal/pb/chatto/core/v1/event.pb.go
#	docs/adr/INDEX.md
#	docs/architecture/interfaces.md
hmans added a commit that referenced this pull request Aug 11, 2026
* origin/main:
  feat(messages): add pinned channel messages (#1990)
  docs(events): document integration and logging contracts (#2004)
  fix(events): guard single-run lifecycles (#2003)
  fix(events): add bounded subject reads (#2002)
  fix(events): validate snapshot bindings (#2001)
  fix(events): require pointer projections (#2000)
  fix(events): make nil loggers safe (#1999)
  ci: run pull request workflows for stack bases (#1998)
  feat(auth): add server invite links (#1983)
  fix(i18n): restore regional locale fallback chains (#1987)
  feat(rooms): allow flexible Unicode names (#1986)
  feat(rooms): add slow mode (#1980)
  chore(agent): add session wrap-up skill (#1981)
  fix(workers): harden durable recovery (#1978)
  feat(admin): report durable worker health (#1979)
  perf(core): defer server member detail hydration (#1977)
  refactor(core): use durable consumers for cleanup (#1974)
  fix(core): make user key shredding crash-safe (#1973)
  test(e2e): add large-server performance CI (#1976)
  feat(events): add durable pull-worker execution (#1972)

# Conflicts:
#	apps/frontend/messages/de-AT/rbac.json
#	apps/frontend/messages/de-CH/rbac.json
#	apps/frontend/src/lib/components/chat/adminNav.test.ts
#	apps/frontend/src/lib/components/chat/adminNav.ts
#	apps/frontend/src/routes/chat/[serverId]/manage/+layout.svelte
#	cli/internal/core/user_auth_projection.go
#	cli/internal/core/user_projection.go
#	cli/internal/core/user_projection_snapshot_test.go
#	cli/internal/core/users.go
#	cli/internal/evtstream/subjects.go
#	cli/internal/pb/chatto/core/v1/event.pb.go
#	cli/internal/pb/chatto/core/v1/models.pb.go
#	cli/internal/pb/chatto/core/v1/projection_snapshots.pb.go
#	cli/internal/pb/chatto/core/v1/user_events.pb.go
#	docs/adr/INDEX.md
#	docs/architecture/interfaces.md
#	docs/fdr/INDEX.md
#	proto/chatto/core/v1/event.proto
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Server Invite Links

1 participant