Repository navigation
fix(platform-objects): the OAuth register form offers only Web and Native, and its Redirect URLs help states the rule for each type - #25011
Conversation
…tive, and its redirect-URL help states the provider's rule per type Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
…, the help's named hosts and the four-value stored column; add the changeset Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
…the register form's new help texts Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
…today, including its snake-cased third value Claude-Session: https://claude.ai/code/session_01UmqzD97e14iws6hmVhgZ5y Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 3 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 3f42eb2396af9b026cb045e656dedb320ef8e13a && git checkout 3f42eb2396af9b026cb045e656dedb320ef8e13a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 93e6c1a5f8bf256310f9ed477523ff2c90bf1bff fd686be8e05fc588d8ba2ee6538ec6a2a46e5b70 && git checkout -B drift-repro 93e6c1a5f8bf256310f9ed477523ff2c90bf1bff && git merge --no-ff fd686be8e05fc588d8ba2ee6538ec6a2a46e5b70
node scripts/docs-audit/affected-docs.mjs --json 93e6c1a5f8bf256310f9ed477523ff2c90bf1bff
|
席位核对ACCEPT · #24773 half 2b ·
|
Part of #24773: half 2b, the Console form's part of the maintainer's ruling D (
6293344532). Half 1 landed as #24853. Half 2a (theplugin-authregister wrapper forwards the type asapplication_type) landed as #24992 (fbb42d900), which is merged into this branch. The 19.0 refusal ofuser-agent-based/publicstays on the card.Clause-②: no (a form's offering: the register route still accepts every type value it accepted, and nothing on the server reads the action's param options, so no accept set or served shape moves)
Cross-lane:
packages/platform-objectsisdomain:engine. This PR comes from thedomain:servicesseat 2 under the claim's widened half-2b block (6302570331).The help describes the door as #24992 left it. The new Redirect URLs help says a Native application may use
http://localhost. Before #24992 that was false: the route senttype, which the provider drops, so a Native client was judged as Web. Measured both ways on a live showcase (pnpm dev -- --fresh,OS_OIDC_PROVIDER_ENABLED=1, seeded admin), throughPOST /api/v1/auth/sys-oauth-application/register:2dc07452a(without #24992)fd686be8e(with #24992)http://localhost:4001/callbackOAUTH_REGISTER_FAILED, "web clients require https redirect URIs on non-loopback hosts"nativehttp://127.0.0.1:4001/callbacknativehttp://[::1]:4001/callbacknativehttp://localhost:4001/callbackhttps://app.example.com/callbackwebwebuser-agent-based+ httpswebweb, one server warningpublic+ httpswebweb, one server warningWhat changes
sys_oauth_application.create_oauth_application(Setup › OAuth Applications › Register), insys-oauth-application.object.ts:objects.generated.tsbundles were regenerated withpnpm i18n:extract. The zh-CN, ja-JP and es-ES values of the two help texts were translated by hand, then extract was run again: the source-hash companions end unchanged, because the new leaves are translations, not copies.typeselect (:449at this head,:425at4b8f597ba), thepublicboolean column, the register route, and every other line of the file.Stop condition: does anything on the server refuse a value the form no longer offers? No.
Measured on the same live showcase at
2dc07452a, and the register-route rows again atfd686be8e(table above):POST /api/v1/auth/sys-oauth-application/registerwithtype: 'user-agent-based'and withtype: 'public'(https redirect): both200,success: true.POST /api/v1/actions/sys_oauth_application/create_oauth_applicationwithtype: 'user-agent-based':400 VALIDATION_ERROR, "istype: 'api'— it dispatches ontarget, not through the action registry". The same answer fortype: 'web'(control). The door refuses anapiaction by its type before its param contract runs (headlessActionTypeErrorinpackages/runtime/src/domains/actions.ts, ahead ofenforceActionParams). The MCPrun_actiondoor refuses it the same way (isHeadlessInvokableAction,action-execution.ts).body.typefrom the raw request and never reads the object's metadata. The middleware seam hands middleware no body. Nothing else matches an action'starget.GET /api/v1/meta/object/sys_oauth_applicationnow serves thetypeparam with options["web", "native"]and the new help texts. With?locale=zh-CNit serves the zh-CN texts and optionsWeb 应用/原生应用.The rule the help states, measured on the provider
@better-auth/oauth-provider1.7.3,validateClientRedirectUri(dist/authorize-9whjxVLJ.mjs:1685). #24992's pins cover Web +http://localhostrefused, Web + https accepted, Native +http://localhost:4001andhttp://127.0.0.1:4001accepted, and Native +http://127.0.0.2:4001andhttp://app.example.comrefused. The rest of what the help says was measured live through the provider's ownPOST /api/v1/auth/oauth2/create-client, at2dc07452a:http://[::1]:4001/callbacknativehttp://localhost:59999/callbackhttp://127.0.0.1/callback(no port)https://app.example.com/callbackhttps://localhost:4001/callbackinvalid_redirect_uri, "native clients must not use https loopback redirect URIs"http://127.0.0.2:4001/callbackhttps://localhost:4001/callbackhttps://127.0.0.1:4001/callbackhttps://app.example.com/callbackThe help does not mention Native private-use URI schemes, which the rule also allows. Nothing here measured them through the route.
The stored columns, measured (for the 19.0 card)
type. Onlywebornative.checkOAuthClientrefuses any otherapplication_type(:1770). One more case: a client-metadata-document registration that names noapplication_typestoresnull(:1956). Live, at2dc07452a: the registrations above nameduser-agent-basedandpublicwere storedtype: 'web',token_endpoint_auth_method: 'client_secret_basic'(8 rows read throughGET /api/v1/data/sys_oauth_application). Again atfd686be8e: 6 rows, the same columns.public. Never. The client record has no such field (OAUTH_CLIENT_RECORD_FIELD_NAMES,:1034). No row carries apublicvalue (8 at2dc07452a, 6 atfd686be8e). A public client istoken_endpoint_auth_method: 'none'.typeselect actually declares. The values areweb,native,useragentbased,public. The column usesField.select's string-array shorthand, which snake-cases each value and strips the hyphens. So the third declared value has never beenuser-agent-based: not the value the form's action param sent, and not the one the provider's earlier lines accepted (from the SDK and dynamic registration, for public clients). A row holdinguser-agent-basedis already outside the declared set today. Keeping the column four-valued in 18.x protectspublic, notuser-agent-based. The pin below holds the column exactly as declared. Fixing it, or narrowing it, is the 19.0 card's decision.Tests
New
packages/platform-objects/src/identity/oauth-register-form-types.test.ts, 7 cases. It reads the object and the four bundles from source.typeparam is a required select, defaults toweb, and offers exactlywebandnative. Every shipped locale's options are exactlywebandnative.https://,http://,localhost,127.0.0.1and[::1]. The Application Type help names Native andhttp://localhost.typeselect still declares its four options (labelsweb,native,user-agent-based,public; values as measured above). Thepubliccolumn is still a declared boolean.Results at
2dc07452a.packages/platform-objectsand this PR's changeset are byte-identical atfd686be8e: the second merge brought only #24992's threeplugin-auth/ changeset files.pnpm --filter @objectstack/platform-objects exec vitest run --maxWorkers=2:Test Files 83 passed (83),Tests 1239 passed (1239).pnpm --filter @objectstack/platform-objects typecheck: exit 0.check:test-typecheck: OK, 1 file / 3 errors / 2 pinned signatures held. No debt added. The new file is in thetsconfig.test.jsonprogram (--listFilesOnly, 1 hit).Ablation (one-shot; no permanent file)
Each leg went through
scripts/ablation-replace.mjs, in a runner with its own EXIT/INT/TERM trap. Each anchor hit once and fell 1 → 0, with the blob changed on disk. Each restore was verified as blob == HEAD withgit diff HEADempty (object240ded11b, zh-CN bundle5326f33a2). The test reads source, so nodistis involved.{ label: 'User-agent based', value: 'user-agent-based' }put back on the action'stypeoptionsexpected [ 'web', 'native', 'user-agent-based' ] to deeply equal [ 'web', 'native' ]http://; the en bundle no longer mirrors the sourcetypeselect narrowed to['web', 'native']zh-CN redirectURLs help ... to contain 'http://'public: "公共客户端"put back in zh-CN's action optionszh-CN type options: expected [ 'web', 'native', 'public' ]publiccolumn renamedis_publicexpected undefined to be 'boolean'Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackat the final headfd686be8ederived 66 commands for 7 paths (208 changed lines, +185 / -23, under the 3000 human-merge threshold). Each ran ascmd > log 2>&1; rc=$?, after a workspace build (turbo run build --filter=!@objectstack/docs).check:adr-0087-registration --base origin/main("this PR adds no declared-breaking changeset"),check:changeset-no-major,check:empty-changeset,check:i18n("all bundles in sync, no undeclared authoring keys"),check:i18n-stale-fill("0 stale-fill leaf/leaves"),check:nul-bytes,check:doc-authoring,check:closing-keyword-parity,check:issue-citations,check:type-check-debtandcheck:dual-build-cjs-loads.--ranwith every exit code recorded:Run reconciliation — 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN.2dc07452a, before fix(plugin-auth): the register form's Application Type reaches the OAuth provider as application_type #24992 was merged in: 66/66 exit 0, reconciled the same way.test:repois CI'sTest Core.check:skill-frame-freshnessdoes not apply: no frame file is touched.check:dev-prereqspassed as the first step of eachpnpm devboot. No exported symbol was renamed or removed, socheck-platform-checklist --changed-fromdoes not apply. The workspace type-check lanes and the CI jobs thatdispatch-gateslists outside the 66 are CI's.Acceptance notes
web/native(ornullfor a metadata-document client) totypeand never writespublic. The declared third value isuseragentbased, notuser-agent-based.Field.select's string shorthand strips hyphens from values (spaces become underscores; a hyphen is dropped). Measured from builtdist:sys_oauth_application.typedeclaresuseragentbased.sys_metadata_audit.lock_state(packages/metadata-core/src/objects/sys-metadata-audit.object.ts:190) declaresnooverlay/nodelete, while its writer (recordMetadataAudit,packages/metadata-protocol/src/protocol.ts) writesno-overlay/no-delete. That column isreadonly: true, so the record validator judges only its shape and the audit writes are not refused. Source reading only; no wrong answer was measured through a door. Reported to the seat in the dev report, not filed here.Generated by Claude Code