Org controls
WorkOS SSO sign-in, a Clerk session-verification driver, owner-gated multi-user membership, and the cross-tenant admin-write RLS layer the operator control plane mutates through.
@caisson-sh/org-controls is the org and operator-controls module, carved out of the
base substrate so the core stays small: WorkOS SSO, a Clerk session-verification
driver, the MANAGE half of the multi-user account model, and the admin-write RLS layer an
operator control plane mutates through. Session resolution stays in the open
@caisson-sh/auth; tenant isolation stays in the open @caisson-sh/tenancy-rls.
What it does
- WorkOS SSO (
createWorkosSsoProvider), a framework-agnostic AuthKit/SSO transport seam: builds the authorization URL, exchanges the callback code for the user's id + email. Config is injected, never read from env by the package. - Clerk session verification (
createClerkSessionVerifier), verifies a Clerk session token against Clerk's JWKS via@clerk/backend, then maps the claims onto the kernel'sSessionContext. Networkless when you supplyjwtKey. - Owner-gated membership (
listAccountMembers/addAccountMember/removeAccountMember/assertCanManageMembers), invite and remove seats on a shared account, owner-only. - Admin-write RLS (
withAdminWrite+ the policy builders), the cross-tenant write role an operator control plane mutates through, DB-separated from the tenant-scopedapprole. - A feature-gate predicate (
holdsOrgControls), a fail-closed check your app can use to gate access to this module's surfaces by whatever grant/entitlement model you run.
Install
bun add @caisson-sh/org-controlsQuickstart, WorkOS SSO
import { createWorkosSsoProvider } from "@caisson-sh/org-controls";
const sso = createWorkosSsoProvider({
clientId: process.env.WORKOS_CLIENT_ID!,
apiKey: process.env.WORKOS_API_KEY!,
redirectUri: "https://app.example.com/auth/callback",
});
const url = sso.authorizationUrl(state); // redirect the user here
const { userId, email } = await sso.exchangeCode(code); // on the callbackClerk session verification
import { createClerkSessionVerifier } from "@caisson-sh/org-controls";
const verifier = createClerkSessionVerifier({
jwtKey: process.env.CLERK_JWT_KEY!, // networkless — no per-call JWKS fetch
authorizedParties: ["https://app.example.com"],
});
const session = await verifier.verifySession(clerkToken); // -> SessionContextAn active Clerk Organization maps to accountId/role; with no Organization active, the
session falls back to the personal-account convention (accountId === userId, role
"owner"). This mapping is stateless, route the verified userId through @caisson-sh/auth's
resolveUserAccounts/selectActiveAccount when you need the DB-authoritative multi-account
resolution instead.
Membership management
import { addAccountMember, listAccountMembers } from "@caisson-sh/org-controls";
// actorRole comes from the caller's resolved session; only "owner" may manage members.
await addAccountMember(db, actorRole, accountId, newUserId); // default role "seat"
const members = await listAccountMembers(db, accountId);Admin-write RLS
import {
withAdminWrite,
buildAdminWritePolicySql,
} from "@caisson-sh/org-controls";
// At DEPLOY, alongside the table's existing tenant-isolation policy:
const sql = buildAdminWritePolicySql("account");
// At call time, in the operator control plane only:
await withAdminWrite(db, async (tx) => {
await tx.query(`UPDATE account SET ... WHERE id = $1`, [accountId]);
});withAdminWrite refuses a SUPERUSER/BYPASSRLS role before it ever assumes it, a
misconfigured role fails closed rather than silently widening access.
Feature-gate predicate
import { holdsOrgControls } from "@caisson-sh/org-controls";
if (!holdsOrgControls(activeEntitlementIds)) {
throw new AuthzError("org-controls access required");
}activeEntitlementIds must already be filtered to active grants, the predicate never reads
the database itself, and an empty set denies.
Composing with the base
org-controls composes DOWN onto @caisson-sh/auth, @caisson-sh/tenancy-rls, and
@caisson-sh/kernel: session resolution and tenant isolation are never
reimplemented here, only extended: the owner-only MANAGE surface and the cross-tenant
admin-write role sit beside those open primitives, never in place of them.
org-controls is a standalone module (also included in the Everything family). Gate access to
its surfaces with holdsOrgControls.
registry-schema
The open registry contract, the module-manifest schema, the built catalog index schema, and the closed feature-tag registry the generator and the MCP server validate against.
Billing orchestration
The multi-provider payment drivers, provider-to-domain-event parsers, and dual-layer webhook idempotency composed on top of the open BillingProvider port.