Skip to content

Identity: the platform's OIDC provider emits the standard locale claim at userinfo (profile scope), so a hosted environment's JIT sign-in follows the cloud account language #25529

Closed

Description

@objectstack-fleet

Filing gate ②: the framework half of the ruling the maintainer gave on objectstack-ai/cloud#3125 (batch #387 item 1, column 现在立 card 5: 「用户语言偏好随云账号进入每个环境」, platform first). This is the producer half that #25261 (the reader, landed as 829cb779) assumed exists. Filed by repo:cloud#1 (seat post #6026, session session_01FSg7JRUiTPo8GrgT38tAWP). ⛔ Not a claim.

Reader who acts: the objectstack lane. objectstack-ai/cloud#3159, the cloud half, is Blocked-by: this card. It resumes as a pin bump plus a local-stack reading.

Measured (pinned tree f0fdd45bbc83, better-auth 1.7.12, @better-auth/oauth-provider 1.7.12)

The source is the cloud dev report on objectstack-ai/cloud#3159 (comment 6373436798).

Wanted

  • In plugin-auth's oauthProvider({...}), add customUserInfoClaims. It returns { locale } when the granted scopes include profile and the user's sys_user.locale (read through the data engine, in system context) is a non-empty BCP-47 tag. Otherwise it returns nothing.
  • ⛔ No new host configuration key and no new column. Every ObjectStack OP emits the standard claim (OIDC Core 5.1), not only the cloud's.

Acceptance

Dedupe

repo:objectstack-ai/objectstack userinfo locale claim returns 1 hit: #25261 (closed, the RP reader; it does not cover the OP). No other card was found.

Activity

  1. added
    enhancementNew feature or request
    domain:serverDomain lane — seat card indexed by label:pm:seat
    area:identityLogin and identity — sign-up, sessions, organization membership, SSO
    pm:queueReady for the PM dispatch loop
    on Oct 23, 2026
  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 6 · card thread
    Session: session_01R1q2xdtYgU6FKrZ7LgjPCC (the seat); the card thread is session_01XCJ2r3w7jCsheYguravx4H
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-v17ls7 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#1
    Ruling-ref: the card's Wanted: plugin-auth's oauthProvider gains customUserInfoClaims returning { locale } only under the profile scope and a non-empty BCP-47 sys_user.locale read through the data engine in system context; userinfo only, ⛔ not the ID token; ⛔ no new host key, column or additionalField
    File surface: packages/plugins/plugin-auth/** (auth-manager.ts's OP composition and a claims helper), its tests, one changeset. ⛔ No packages/spec/** (stop on breach; explain in the report)
    Container & model: M, mode:thread, default model and effort (set at thread open)
    Clause-②: yes (expected: an added standard claim; the dev measures)
    Metadata-protocol: none
    Responsibility: a hosted environment's JIT sign-in never receives locale, because the platform OP passes no customUserInfoClaims, so #25261's RP reader never fires on the cloud path (card #25529, pinned tree f0fdd45bbc83)
    Thread-read: none
    Premise: holds (read 2026-10-26T08:15Z at origin/main 05f7758f05: card open, unassigned, pm:queue, no other seat's claim; the dev reproduces red first)
    Serial constraints cleared: no open PR names #25529; the dev re-measures open PRs on its file surface before pr_create

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 26, 2026
  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 25529,
      "status": "done",
      "branch": "claude/project-thread-v17ls7",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26012",
      "session": "session_01XCJ2r3w7jCsheYguravx4H",
      "premise_still_valid": true,
      "summary": "plugin-auth's oauthProvider composition (now auth-manager-plugin-list.ts:500; auth-manager.ts:4252 on the filing tree moved there in the split) gains customUserInfoClaims, which returns { locale } only when the access token's scopes include profile and sys_user.locale, read through the data engine in system context, passes normalizeRecipientLocale; otherwise {}. The rule lives in the new oidc-userinfo-locale-claim.ts. Userinfo only (the ID token is asserted locale-free); no host key, column or additionalField. A failed read omits the claim and warns once via the host logger with the user id. Measured: better-auth and @better-auth/oauth-provider are 1.7.12 on main; customUserInfoClaims(info: { user, scopes, jwt, requestedClaims }) exists there and its result is merged after the provider's claims with sub re-pinned.",
      "tests": "New oidc-userinfo-locale-claim.test.ts drives a REAL AuthManager OP (oidcProvider on, shared in-memory engine) over HTTP: sign-up, create-client, authorize+PKCE, consent, token, userinfo; plus one RP round trip end to end (second AuthManager as the platform RP, genericOAuth objectstack-cloud via OIDC discovery, fetch routed to the OP handler) where the RP JIT path stores zh-CN. Red on main+test (b6c90526): 3 failed / 13 passed (zh-CN leg: expected undefined to be 'zh-CN'; read-failure leg: warn called 0 times; round trip: RP user locale undefined). Green at 630e39c2: 16/16. Ablation via scripts/ablation-replace.mjs (anchor 'customUserInfoClaims: ({ user, scopes }) =>' renamed; test resolves src, no dist): anchor 1->0, blob dade996dd516->2de5c1541934, same 3 legs red, restored to HEAD blob dade996dd516, git diff HEAD empty. pnpm --filter @objectstack/plugin-auth typecheck exit 0 (check:test-typecheck OK, no new test-layer errors); full plugin-auth vitest 196 files / 3737 passed / 10 skipped exit 0; eslint --no-inline-config packages/plugins/plugin-auth exit 0.",
      "gates": "Local, head 630e39c2: dispatch-gates --commands = 68 commands, each exit captured before any pipe; --ran reconciliation 68 derived / 68 run / 0 NOT-MEASURED, exit 0. First-run exit 3 (prerequisite, nothing measured) re-run green: check-plugin-teardown-shape --self-test (shallow clone; control commit fetched), check:dual-build-cjs-loads (after turbo build 120/120), check:type-check-debt (lock budget spent behind my build). Also check:dts-closure re-run green post-build. CI check-runs on #26012: in_progress at report time (not re-run locally).",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP calls; reads went through REST",
      "api_writes": "2 relay actions — pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST .../issues/26012/assignees os-project-manager) via fleet-write run 40296768726; this os-dev-report comment (POST .../issues/25529/comments via post-stamped). Plus git pushes (not REST).",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none — noted in PR Acceptance notes only: discovery claims_supported does not list locale (the provider overwrites its claims list from its own standard-claim table; only advertisedMetadata.claims_supported would replace it wholesale). OIDC Discovery makes the list RECOMMENDED and non-exhaustive, and the platform RP never reads it; zero-pull, not filed.",
        "carrier: none — open PR #25983 (spec: a locale must be a BCP-47 tag) touches no file on this surface; re-measured all 20 open PRs, none touches packages/plugins/plugin-auth/src."
      ],
      "clause2": "Clause-②: yes / Metadata-protocol: none / changeset patch on @objectstack/plugin-auth — as the claim; measured: an added standard claim widens the userinfo response, no author-facing metadata key."
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed

    PR #26012 merged at 2026-10-26T10:00Z by the merge queue as 431f065177 on main (Fixes #25529; ACCEPT 6412370789).

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-26012-*' 0 refs
    origin/main by content git cat-file -e origin/main:packages/plugins/plugin-auth/src/oidc-userinfo-locale-claim.ts present
    Ancestry git merge-base --is-ancestor 431f065177 origin/main holds

    State: this card closed by Fixes (completed); pm:dispatched removed.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:identityLogin and identity — sign-up, sessions, organization membership, SSOdomain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions