Commit 71b2687
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 ef079b3 commit 71b2687
18 files changed
Lines changed: 1086 additions & 146 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 | | |
| |||
595 | 596 | | |
596 | 597 | | |
597 | 598 | | |
| 599 | + | |
| 600 | + | |
598 | 601 | | |
599 | 602 | | |
600 | 603 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1560 | 1560 | | |
1561 | 1561 | | |
1562 | 1562 | | |
| 1563 | + | |
| 1564 | + | |
| 1565 | + | |
| 1566 | + | |
| 1567 | + | |
| 1568 | + | |
| 1569 | + | |
| 1570 | + | |
| 1571 | + | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
1563 | 1575 | | |
1564 | 1576 | | |
1565 | 1577 | | |
1566 | 1578 | | |
| 1579 | + | |
| 1580 | + | |
| 1581 | + | |
| 1582 | + | |
| 1583 | + | |
| 1584 | + | |
1567 | 1585 | | |
1568 | 1586 | | |
1569 | 1587 | | |
| |||
| 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