Skip to content

feat(plugin-auth): cap self-created orgs per user (OS_ORG_LIMIT)#2357

Merged
xuyushun441-sys merged 1 commit into
mainfrom
feat/org-limit
Jun 27, 2026
Merged

feat(plugin-auth): cap self-created orgs per user (OS_ORG_LIMIT)#2357
xuyushun441-sys merged 1 commit into
mainfrom
feat/org-limit

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

What

Adds a configurable per-user cap on self-created organizations, forwarded to better-auth's organizationLimit.

  • New resolveOrgLimit() (@objectstack/types) reads OS_ORG_LIMIT; unset → unlimited (self-host default).
  • plugin-auth passes organizationLimit in function form, counting only the caller's role=owner memberships (orgs they created) — read via withSystemReadContext so the cross-tenant sys_member count isn't filtered to empty by org-scoping. Fail-open if the count can't be taken.

Why

Enabling multi-org (OS_MULTI_ORG_ENABLED) lets a user create orgs, and on the cloud control plane every new org auto-provisions a free environment (a real DB). Without a cap, one account could script createOrganization to spawn unbounded free DBs.

better-auth's number form counts all of a user's memberships, which would wrongly block a collaborator invited into many orgs from creating their own. Owner-scoped counting is the correct axis. No-op in single-org mode (create is already denied by beforeCreateOrganization).

Verified (local rig)

  • A user owning 4 orgs but a member of 5 is allowed to create at OS_ORG_LIMIT=5 (the invited org is not counted).
  • Once they own 5, the next create is blocked (403 “maximum number of organizations”).

🤖 Generated with Claude Code

Forward better-auth's `organizationLimit` in FUNCTION form, counting only the
caller's `role=owner` memberships (orgs they created) — never orgs they were
invited into — read via `withSystemReadContext` so the cross-tenant `sys_member`
count isn't filtered to empty by org-scoping. Threshold from `OS_ORG_LIMIT`
(new `resolveOrgLimit()`); unset → unlimited (self-host default). Fail-open if
the count can't be taken, so an infra hiccup never blocks a legitimate user.

Why owner-scoped, not a flat count: better-auth's number form counts ALL of a
user's memberships, which would block a collaborator invited into many orgs from
creating their own. We only want to bound scripted org/free-env spam (each new
org auto-provisions a free environment on the cloud control plane), so capping
self-created orgs is the right axis. No-op in single-org mode (create is already
denied by beforeCreateOrganization).

Verified on the local rig: a user owning 4 orgs but a member of 5 is allowed to
create at limit=5 (the invited org is not counted), then blocked once they own 5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 27, 2026 8:15am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-auth, @objectstack/types.

10 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/implementation-status.mdx (via @objectstack/plugin-auth)
  • content/docs/concepts/packages.mdx (via @objectstack/plugin-auth, @objectstack/types)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/auth-sso.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/authentication.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/kernel-services.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/packages.mdx (via @objectstack/plugin-auth, @objectstack/types)
  • content/docs/guides/plugins.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-auth)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@xuyushun441-sys xuyushun441-sys merged commit 27af33a into main Jun 27, 2026
16 checks passed
@xuyushun441-sys xuyushun441-sys deleted the feat/org-limit branch June 27, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants