Skip to content

Let owners of the self-host root organization create organizations - #82

Open
shuv1337 wants to merge 1 commit into
feat/selfhost-multi-orgfrom
feat/selfhost-multi-org-creation
Open

shuv1337 wants to merge 1 commit into
feat/selfhost-multi-orgfrom
feat/selfhost-multi-org-creation

Conversation

@shuv1337

@shuv1337 shuv1337 commented Nov 5, 2026

Copy link
Copy Markdown
Owner

Why

Self-host is getting real multi-organization support where only owners of the root organization, the one setup created, may create organizations. This PR turns creation on with that rule enforced by the server. Stacked on #81, which must ship and be verified in production first: an older server locks everyone out once a second organization exists.

What changed

  • allowUserToCreateOrganization asks selfHostRoot().ownsRoot(user.id): the selfHostRoot record must exist and the user's membership in that organization must have role owner. No record, or any other role, is a refusal.
  • The root plugin captures Better Auth's adapter in init, because the library calls this option with only the user.
  • Better Auth's create endpoint requires a session on every HTTP request (ctx.request with no session is 401), and API keys have enableSessionForAPIKeys: false, so bearer keys and OAuth tokens cannot create.
  • The creator becomes the new organization's owner (creatorRole default).
  • Docs: self-host page describes who can create.

Decision recorded from Lauren (relayed): root-organization owners only, not owners of any organization; an install with several organizations and no root record fails closed.

Verification

bun run check: exit 0.

self-host-organization-creation.spec.ts (new), 3/3 passed on self-host:

  • Authority matrix: the root owner creates (200) and is the only member, with role owner. Refused: admin 403, member 403, someone invited only into the new organization 403, that person after being made owner of the new organization 403, anonymous 401, the owner's API key as a bearer 401. The denied attempts created nothing.
  • Bootstrap: zero organizations, so setup: true. Setup gives 200, then setup: false and a second setup 403. Two creations follow, setup is still 403, and the root record is the setup organization. After a restart setup is still 403 and the owner creates a fourth.
  • Without a root: an install upgraded with one organization records it and its owner creates. With two organizations and the root record and journal removed, the upgrade leaves no root, so the setup owner gets 403, still after a restart.

Negative check: with the rule weakened to "owner of any organization", the authority scenario fails at line 135 (expected 200 to be 403, the owner of a non-root organization).

#81's scenarios and invitation-roles rerun on this branch: 5/5 passed.

The fork CI runs only for pull requests into v2, so it runs here once #81 merges and this is retargeted.

self-host-organization-creation.spec.ts
self-host-many-organizations.spec.ts
invitation-roles.spec.ts

Better Auth's create endpoint now asks whether the signed-in user owns the
root organization that setup recorded. Admins, members, people outside the
root, owners of other organizations, anonymous callers and bearer keys are
refused, and an install with no root record refuses everyone. The creator
becomes the new organization's owner.

Co-authored-by: Cursor <cursoragent@cursor.com>
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.

1 participant