Repository navigation
fix(auth): keep a static client's SEP-2352 issuer stamp across saves and restarts - #2794
Merged
Merged
Conversation
…and restarts (#2751) The SDK back-stamps the preregistered client via saveClientInformation(info, { issuer }), which routed into a per-issuer dynamic slot that the preregistered read never consults, and re-seeding the static client at startup overwrote the slot anyway. The binding was lost and the SDK warned on every run. - Route an SDK save whose client_id matches the preregistered client to the preregistered slot, and return the stamp from the preregistered read (it has no byIssuer key to recover it from). - Re-seeding carries the stamp over while client_id and client_secret are unchanged; a changed client starts unstamped. - A stamp naming a different issuer is handed back unstamped, so the static client is re-bound rather than discarded on an AS migration, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
There was a problem hiding this comment.
🟡 Changes recommended
The restart regression test must reload a persisted snapshot through fresh storage rather than reuse in-memory state.
1 open issue
What changed in this PR
Fixes #2751 by preserving a static OAuth client’s SEP-2352 issuer stamp in Inspector’s shared authentication layer.
Changes:
- Routes SDK back-stamps to the preregistered client and restores stamps on reads.
- Preserves stamps when re-seeding unchanged credentials while retaining authorization-server migration behavior.
- Adds provider and SDK authorization regression tests.
| File | Description |
|---|---|
| core/auth/storage.ts | Accepts stamped preregistered client information in the storage contract. |
| core/auth/providers.ts | Routes back-stamps, preserves stamps during re-seeding, and handles issuer changes. |
| core/auth/oauth-storage.ts | Restores the stored issuer stamp after schema parsing. |
| clients/web/src/test/core/auth/providers.test.ts | Adds static-client stamp and SDK authorization regression coverage. |
Review effort: Balanced
…gression (#2751) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
Member
Author
|
Copilot round 1: one finding, fixed.
|
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.

Closes #2751
Problem
For a static (preregistered) OAuth client, the SDK's SEP-2352 issuer back-stamp,
saveClientInformation(info, { issuer }), went throughresolveSdkRegistrationKindinto a per-issuer dynamic slot.clientInformation()reads the preregistered slot first and never looks at that dynamic slot. On top of that, re-seeding the static client at startup overwrote the preregistered slot. So the binding never persisted, and the SDK printed its unstamped-credential warning on every run.Fix (
core/auth/)registrationKind) has aclient_idmatching the stored preregistered client, the provider writes{ ...preregistered, issuer }to the preregistered slot instead (backStampPreregistered).OAuthClientInformationSchemastripsissueron parse, and a static client has nobyIssuerkey to recover the stamp from. SoOAuthStorageBasere-attaches the stamp stored on the value itself. The secret split already keepsissuerin the plaintext residue.savePreregisteredClientInformationcarries an existing stamp over whileclient_idandclient_secretare unchanged. A changed client starts unstamped.ctx.issuer, the client is handed back unstamped, so the SDK re-binds it rather than discarding it. The existingSEP-2352 AS migratione2e test still passes on this path.savePreregisteredClientInformation's parameter and the provider'ssaveClientInformationare now typedStoredOAuthClientInformation, the SDK's stamped type. That is what both actually receive.Tests
clients/web/src/test/core/auth/providers.test.ts, understatic client issuer stamp:client_idstays in its own slotclient_idorclient_secret, and passes an unstamped client through unchangedOAuthStorageBase, the real startup seed and the SDK's ownauth(). The first run warns once and stamps; a simulated restart (new provider, same storage, re-seed) finds the stamp on the preregistered client, nothing in the dynamic slot, and zero SEP-2352 warnings.Five of the new tests fail against the unfixed
core/and pass with it. One existing assertion ("nothing is read at all") was narrowed to "no registration slot is read", since an SDK save now checks the preregistered slot.npm run local:gatepasses. No UI change, so no screenshots.🤖 Generated with Claude Code