fix(auth): add issuer to pre-registration context - #423
Open
logiscapedev wants to merge 1 commit into
Open
Conversation
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #422
What
auth/pre-registrationhands the client under testcontext: { client_id, client_secret }withno indication of which authorization server issued the credentials. The 2026-07-28 spec's
Authorization Server Binding
section says clients using pre-registered credentials MUST associate them with the issuing
authorization server, keyed by its
issueridentifier. A client that takes the strict reading ofthat MUST — refusing to present credentials it cannot bind — never makes a token request, and the
scenario's
pre-registration-authcheck fails ("Client did not make a token request"). Thescenario predates the rule (#120, Jan 2026, before SEP-2352) and was never updated.
This PR additively supplies the mock AS's issuer in the scenario context:
The emitted value equals the issuer the mock AS publishes in its metadata (the scenario sets
neither
metadataIssuernorroutePrefix, socreateAuthServerresolves the published issuer toexactly this URL — pinned by a new self-test). Alongside:
src/schemas/context.ts— theauth/pre-registrationvariant ofClientConformanceContextSchemagainsissuer: z.string().examples/clients/typescript/everything-client.ts—runPreRegistrationdemonstrates theintended use via the provider's existing SEP-2352 helper:
provider.bindIssuer(ctx.issuer).This is the discovery half of what #285/#286 already settled behaviorally: #285 concluded issuer
keying isn't protocol-observable and #286 tests the enforcement side via
auth/authorization-server-migration— indeed #286 shippedbindIssuer()in this repo's ownexample client precisely to key credentials by issuer, yet this scenario gave a client nothing to
key by. Real-world pre-registration always tells the operator which AS issued the credentials; the
scenario now does too. Strict clients become testable; warn-and-proceed clients are provably
unaffected (verified against the TypeScript SDK).
Self-test (prove it passes and fails)
New test in
src/scenarios/client/auth/index.test.ts: the scenario's emitted context parsesagainst
ClientConformanceContextSchemaand itsissuerequals theissuerthe mock AS servesat
/.well-known/oauth-authorization-server— the property a binding client depends on. Thestrict-refusal red case is demonstrated with a real SDK below.
npm test484/484,npm run checkclean.Real-SDK evidence (per CONTRIBUTING)
Strict client (PHP SDK, logiscape/mcp-sdk-php v2
main, draft track = mandatory issuerbinding, no legacy opt-out):
pre-registration-authFAILURE "Client did not make a tokenrequest"; the client refuses: "Pre-registered client credentials have no issuer binding…"
issuerfrom context): 14/14.Warn-path regression (official TypeScript SDK, current
main, via the sdk-runner): passesbefore and after — its conformance client's non-strict context parsing strips the new key, so
behavior is byte-identical.
This repo's example client:
auth/pre-registration14/14 before and after; full--suite auth235/235 before and after (no delta in sibling scenarios).🤖 Generated with Claude Code
Types of changes
Checklist