Skip to content

feat(auth): SSO-only ("enforced") login primitive + identity-source provenance (ADR-0024 D5.2/D4)#2349

Merged
os-zhuang merged 1 commit into
mainfrom
feat/sso-enforced-mode
Jun 26, 2026
Merged

feat(auth): SSO-only ("enforced") login primitive + identity-source provenance (ADR-0024 D5.2/D4)#2349
os-zhuang merged 1 commit into
mainfrom
feat/sso-enforced-mode

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Open mechanism (ADR-0002) for per-deployment SSO-only ("enforced") login — drives the cloud per-env enforced mode AND self-host OSS/EE (via OS_AUTH_SSO_ONLY). Generic over the IdP (cloud-as-IdP or a customer's own OIDC/SAML). Inert until a consumer sets ssoOnlyMode.

What

  • AuthConfig.ssoOnlyMode + AuthFeatures.ssoEnforced (spec). When on: emailAndPassword.disableSignUp forced true + /auth/config emits features.ssoEnforced so the login UI hides the local password form + self-registration. enabled stays true → the env owner keeps a break-glass password escape hatch (managed users simply hold no credential). Self-host knob OS_AUTH_SSO_ONLY mirrors the existing OS_DISABLE_SIGNUP pattern.
  • sys_user.source (idp-provisioned|env-native, ADR-0024 D4 provenance), stamped by a framework-generic account.create.after hook composed with any host databaseHooks. Break-glass safe + idempotent: a user holding a local credential stays env-native; a credential gained after an SSO link flips a previously-managed owner back (covers the owner-set-password-after-first-SSO timing).
  • Managed-vs-native gating: change_my_password / change_my_email / delete_my_account hide for idp-provisioned users (can't self-mint a local password that bypasses enforced SSO).
  • Break-glass guard: refuse to delete/ban the last holder of a local credential (LAST_LOCAL_CREDENTIAL) so an IdP outage can never lock the org out.

Open-core

Framework = the mechanism (open). The cloud drives ssoOnlyMode per-env + Business+ plan-gating + Free/Team=enforced default (separate cloud PR). Self-host configures via OS_AUTH_SSO_ONLY.

Verify

turbo run build green across all 68 packages (dts/typecheck clean). Browser E2E of the enforced login + managed-vs-native surface lands with the cloud wiring.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 26, 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 26, 2026 2:11pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/spec.

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

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/platform-objects, @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/spec)
  • content/docs/guides/auth-sso.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/authentication.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/external-datasources.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/project-scoping.mdx (via @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/guides/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth, @objectstack/spec)

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.

…rovenance (ADR-0024 D5.2/D4)

Open mechanism (ADR-0002) for per-deployment SSO-only login — drives the
cloud's per-env enforced mode AND self-host OSS/EE (via OS_AUTH_SSO_ONLY).
Generic over the IdP (cloud-as-IdP or a customer's own OIDC/SAML).

- AuthConfig.ssoOnlyMode + AuthFeatures.ssoEnforced (spec). When on:
  emailAndPassword.disableSignUp is forced true + /auth/config emits
  features.ssoEnforced so the login UI hides the local password form +
  self-registration. `enabled` stays true → the env owner keeps a break-glass
  password escape hatch (managed users simply hold no credential).
- sys_user.source (idp-provisioned|env-native, ADR-0024 D4 provenance),
  stamped by a framework-generic account.create.after hook composed with any
  host databaseHooks. Break-glass safe + idempotent: a user holding a local
  credential stays env-native; a credential gained after an SSO link flips a
  previously-managed owner back.
- Managed-vs-native gating: change_my_password / change_my_email /
  delete_my_account hide for idp-provisioned users (can't self-mint a local
  password that bypasses enforced SSO).
- Break-glass guard: refuse to delete/ban the LAST holder of a local
  credential (LAST_LOCAL_CREDENTIAL) so an IdP outage can never lock the org out.

Inert until a consumer sets ssoOnlyMode (cloud per-env / OS_AUTH_SSO_ONLY).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@os-zhuang
os-zhuang force-pushed the feat/sso-enforced-mode branch from 106b478 to 1ce8963 Compare June 26, 2026 14:08
@github-actions github-actions Bot added the tests label Jun 26, 2026
@os-zhuang
os-zhuang merged commit 73f4dc7 into main Jun 26, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the feat/sso-enforced-mode branch June 26, 2026 14:20
os-zhuang added a commit to objectstack-ai/objectui that referenced this pull request Jun 26, 2026
…R-0024 D5.2) (#2012)

Consumes the framework's new `/auth/config` `features.ssoEnforced` signal
(objectstack-ai/objectstack#2349). When the server locks the team login to the
IdP, LoginForm now:

- hides the local email/password form + the sign-up link,
- shows the federated button(s) only (SocialSignInButtons — e.g. "Continue
  with ObjectStack" for cloud-as-IdP, or an external OIDC/SAML provider),
- offers an understated **break-glass** "Use a password instead" link that
  reveals the password form for the env owner / local admin (e.g. during an
  IdP outage), with a "Back to single sign-on" toggle.

`emailPassword.enabled === false` is honored as a belt-and-suspenders enforced
signal for older servers. Default-off: a failed `/auth/config` fetch never
hides the form. New i18n labels (usePasswordText / backToSsoText /
ssoOnlyDescription). 4 new LoginForm tests; full auth suite green (115).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant