Skip to content

fix(auth): resolve OIDC-gate session hook-order-independently (D5.1)#2345

Merged
os-zhuang merged 1 commit into
mainfrom
fix/oidc-gate-session-resolve
Jun 26, 2026
Merged

fix(auth): resolve OIDC-gate session hook-order-independently (D5.1)#2345
os-zhuang merged 1 commit into
mainfrom
fix/oidc-gate-session-resolve

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Follow-up to #2343. The gate before-hook resolved the subject only via getSessionFromCtx, which returns null in a global before-hook for a bearer request (the bearer plugin converts Authorization→session after this hook), so the gate was skipped (fail-open). Adds explicit token resolution (bearer / session-cookie token) + sys_session lookup, hook-order-independent.

🤖 Generated with Claude Code

The oidcAuthorizeGate before-hook resolved the subject only via getSessionFromCtx,
which can return null in a global before-hook for a bearer (or non-default-cookie)
request — the bearer plugin may convert Authorization -> session AFTER this hook
runs, leaving gateUserId undefined so the gate was skipped (fail-open). Add an
explicit token resolution (bearer, or the session cookie's token part) + a
sys_session lookup, independent of plugin hook order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@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 Building Building Preview, Comment Jun 26, 2026 12:07pm

Request Review

@os-zhuang
os-zhuang merged commit e360c9e into main Jun 26, 2026
9 of 10 checks passed
@os-zhuang
os-zhuang deleted the fix/oidc-gate-session-resolve branch June 26, 2026 12:07
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-auth.

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)
  • 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)
  • 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.

os-zhuang added a commit that referenced this pull request Jul 9, 2026
…ing to enterprise (#2699)

* chore: bump objectui to 195121ade6ec

feat(studio): match form designer/preview column density to the runtime form (#2345)

objectui@195121ade6ec921e5786030093f0b23fc58d02f7

* feat(auth,platform-objects): open single-org org-management basics (cloud ADR-0081 D1)

Single-org deployments had NO way to add a user at all: the invite
affordances hid behind 'features.multiOrgEnabled' gates, and nothing ever
created an organization (OrgScopingPlugin and its default-org bootstrap are
multi-org-gated), so sessions carried no activeOrganizationId and better-auth
organization/invite-member had no org to resolve.

- plugin-auth: ensureDefaultOrganization moves here (open home; the
  multi-org seed-ownership step becomes an injectable option that
  plugin-org-scoping's wrapper keeps providing), wired in single-org mode on
  kernel:ready + after every sys_user_permission_set insert
  (autoDefaultOrganization opt-out).
- plugin-auth: default session.create.before hook stamps
  activeOrganizationId from the caller's sys_member row (owner-preferred);
  host-supplied hooks chain first and win (autoActiveOrganization opt-out).
- platform-objects: member/invitation/team actions re-gate from
  'features.multiOrgEnabled' to 'features.organization' (the capability is
  always mounted); sys_organization's own create/leave/delete keep the
  multi-org gate so the single-org default org stays protected.
- setup nav: new nav_organization entry deep-links to the ACTIVE org's
  record page ({current_org_id}); nav_teams / nav_invitations drop the
  org-scoping service gate; the Organizations LIST keeps it (multi-org only).

Live-verified single-org via browser: first-run wizard -> default org
(renamed, CJK name) + owner membership + active-org session; invite ->
accept -> change role -> remove, all through better-auth endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat!: retire plugin-org-scoping — multi-org runtime moves to the enterprise @objectstack/organizations package (cloud ADR-0081 D2)

BREAKING: the open @objectstack/plugin-org-scoping package is removed. The
multi-org runtime (organization_id auto-stamp, per-org seed replay, multi-org
default-org bootstrap) is now the closed-source @objectstack/organizations
package, which keeps registering the historical 'org-scoping' service — the
plugin-security RLS probe and the requiresService nav gates are unaffected.

- cli serve / plugin-dev / verify harness mount it best-effort by name when
  OS_MULTI_ORG_ENABLED=true; a missing package WARNS loudly (serve/dev) or
  throws an actionable error (verify's explicit multiTenant opt-in) instead
  of silently downgrading the RLS posture.
- The open member-management basics are unaffected: plugin-auth's single-org
  default-org bootstrap + better-auth invitations (ADR-0081 D1) keep working
  without the enterprise package.
- dogfood multi-org RLS gate skips (loudly) when the package isn't linked;
  enterprise/cloud CI runs it.

Live-verified: multi-org stack with the enterprise package linked (bootstrap,
second-org create, {current_org_id} nav following org switch) and the
missing-package single-org downgrade warning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(verify,changeset): keep the verify harness pure single-tenant; drop deleted package from changeset fixed group

- verify harness: pass autoDefaultOrganization: false to AuthPlugin. The
  single-org default-org bootstrap (ADR-0081 D1) is a product onboarding
  convenience for objectstack dev/serve; running it inside the harness minted
  a Default Organization + bound the dev admin as owner, giving every
  'single-tenant' fixture an active org — which switched on org-scoped RLS and
  reparented seeded rows, breaking the pure single-tenant baseline the dogfood
  proofs assert (ADR-0057 identity create, ADR-0062 federation, ADR-0086
  two-doors). The bootstrap stays covered by plugin-auth unit tests + browser E2E.
- .changeset/config.json: remove @objectstack/plugin-org-scoping from the
  fixed group (package deleted in this branch).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant