Commit 6a87d23
committed
feat(client): SEP-2352 per-authorization-server credential isolation (issuer-stamped)
auth() now stamps an `issuer` field onto every value it passes to
saveTokens()/saveClientInformation() and threads {issuer} as the ctx
argument to tokens()/clientInformation(). On read, a stored value whose
stamp names a different authorization server is treated as undefined via
discardIfIssuerMismatch(), so a client_id or refresh_token issued by one
AS is never sent to another — the flow re-registers/re-authorizes
exactly as if nothing were stored.
This replaces the previous detection-and-throw approach with structural
keying: providers that round-trip stored values verbatim are protected
with no code change; multi-AS providers key storage on ctx.issuer.
- New discardIfIssuerMismatch() helper (exported).
- AuthorizationServerMismatchError moved to authErrors.ts; thrown only
on the callback-leg gate (discoveryState issuer \!= resolved issuer).
- console.warn on the callback leg when the provider lacks
saveDiscoveryState().
- saveAuthorizationServerUrl()/authorizationServerUrl() deprecated:
still written for back-compat (Cross-App Access), never read.
- ClientCredentialsProvider/PrivateKeyJwtProvider/
StaticPrivateKeyJwtProvider/CrossAppAccessProvider gain expectedIssuer
and no longer define saveClientInformation().
- examples/oauth: single-slot blob storage + discoveryState.
- Conformance: provider implements discoveryState/invalidateCredentials;
handle401 clears discovery on 401 so AS migration is re-probed;
runAuthClient uses versionNegotiation:auto so the
auth/authorization-server-migration scenario (and the 2026-leg
scope-step-up/scope-retry-limit) speak the modern lifecycle.
- ~6 focused unit tests + 5 e2e as-migration:* rows asserting structural
behaviour (no token POST to wrong AS because the stamp read returned
undefined).
Claude-Session: https://claude.ai/code/session_01XBib5gRe8AMPPJhySCz3EJ1 parent 0bae633 commit 6a87d23
18 files changed
Lines changed: 1088 additions & 147 deletions
File tree
- .changeset
- docs
- examples/oauth
- packages/client
- src
- client
- test/client
- test
- conformance
- src
- helpers
- e2e
- scenarios
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
223 | 223 | | |
224 | 224 | | |
225 | 225 | | |
| 226 | + | |
226 | 227 | | |
227 | 228 | | |
228 | 229 | | |
| |||
598 | 599 | | |
599 | 600 | | |
600 | 601 | | |
| 602 | + | |
| 603 | + | |
601 | 604 | | |
602 | 605 | | |
603 | 606 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1633 | 1633 | | |
1634 | 1634 | | |
1635 | 1635 | | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
| 1644 | + | |
| 1645 | + | |
| 1646 | + | |
| 1647 | + | |
1636 | 1648 | | |
1637 | 1649 | | |
1638 | 1650 | | |
1639 | 1651 | | |
| 1652 | + | |
| 1653 | + | |
| 1654 | + | |
| 1655 | + | |
| 1656 | + | |
| 1657 | + | |
1640 | 1658 | | |
1641 | 1659 | | |
1642 | 1660 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
2 | 8 | | |
3 | 9 | | |
4 | 10 | | |
5 | | - | |
6 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
7 | 20 | | |
8 | 21 | | |
9 | 22 | | |
10 | 23 | | |
11 | 24 | | |
| 25 | + | |
12 | 26 | | |
13 | 27 | | |
14 | 28 | | |
| |||
66 | 80 | | |
67 | 81 | | |
68 | 82 | | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
69 | 98 | | |
0 commit comments