Commit 3bc0b4c
committed
Derive the expected issuer before fetching authorization server metadata
Discovery now chooses its authorization server, and with it the issuer the
metadata must carry (RFC 8414 section 3.3), before any metadata is fetched:
the PRM-advertised server, or on the 2025-03-26 no-PRM fallback the
resource server's origin, which is what that well-known URL is built from.
The issuer check runs on both paths instead of only when PRM was found; the
SEP-2352 credential binding is decided against that same value before the
fetch, so it also applies when no metadata is served and the default
endpoints are used; newly registered clients are bound to it when metadata
for it was found; and a pass replaces what an earlier pass discovered once
it has chosen a server and looked for its metadata, so nothing left over
from before feeds a later registration. The special case that re-checked the
binding against the served issuer goes away.
A 403 insufficient_scope step-up takes the same path as a 401. Until now it
re-authorized with whatever metadata was in memory, and with none after a
restart, in which case it used the 2025-03-26 default endpoints on the
resource server's origin regardless of what the server advertises and never
consulted the binding. It now discovers first when no metadata is held
(extract_resource_metadata_from_www_auth also reads the `resource_metadata`
hint from a 403 challenge), re-checks the binding either way, and then
re-authorizes with the SEP-2350 scope union, keeping the granted scope in
the union even when the server changed; metadata already discovered in this
process is reused as before, so for a server that publishes none each
step-up repeats the discovery requests. A 403 that is not a scope challenge
is handed back to the caller instead of being retried unchanged. This is the
shape IdentityAssertionOAuthProvider already uses.
Issuer strings are compared after parsing both sides the way the metadata
`issuer` is parsed (scheme and host case, default ports, IDNA), with one
tolerance beyond that: an origin with an empty path and the same origin
with a lone "/" are the same issuer, since servers commonly render a root
issuer with a trailing slash and both forms yield the same well-known URL.
validate_metadata_issuer, credentials_match_issuer and the new issuers_equal
share that rule. IdentityAssertionOAuthProvider passes the issuer as the
metadata states it to the assertion provider, so the ID-JAG audience is the
server's own spelling either way. docs/migration.md and the identity
assertion page describe the comparison as it now is.
This brings the no-PRM path in line with the TypeScript client, which
applies the section 3.3 check on every discovery path.1 parent 6705402 commit 3bc0b4c
8 files changed
Lines changed: 931 additions & 161 deletions
File tree
- docs
- client
- src/mcp/client/auth
- extensions
- tests/client
- auth/extensions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
59 | 62 | | |
60 | 63 | | |
61 | 64 | | |
| |||
140 | 143 | | |
141 | 144 | | |
142 | 145 | | |
143 | | - | |
| 146 | + | |
144 | 147 | | |
145 | 148 | | |
146 | 149 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2495 | 2495 | | |
2496 | 2496 | | |
2497 | 2497 | | |
2498 | | - | |
2499 | | - | |
2500 | | - | |
2501 | | - | |
2502 | | - | |
| 2498 | + | |
| 2499 | + | |
| 2500 | + | |
| 2501 | + | |
| 2502 | + | |
| 2503 | + | |
| 2504 | + | |
| 2505 | + | |
| 2506 | + | |
| 2507 | + | |
2503 | 2508 | | |
2504 | 2509 | | |
2505 | 2510 | | |
| |||
2508 | 2513 | | |
2509 | 2514 | | |
2510 | 2515 | | |
2511 | | - | |
| 2516 | + | |
2512 | 2517 | | |
2513 | 2518 | | |
2514 | 2519 | | |
2515 | | - | |
| 2520 | + | |
2516 | 2521 | | |
2517 | 2522 | | |
2518 | 2523 | | |
2519 | | - | |
2520 | | - | |
| 2524 | + | |
| 2525 | + | |
| 2526 | + | |
2521 | 2527 | | |
2522 | 2528 | | |
2523 | 2529 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | | - | |
19 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
67 | 68 | | |
68 | 69 | | |
69 | 70 | | |
70 | | - | |
| 71 | + | |
71 | 72 | | |
72 | 73 | | |
73 | 74 | | |
| |||
107 | 108 | | |
108 | 109 | | |
109 | 110 | | |
110 | | - | |
111 | | - | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
112 | 114 | | |
113 | 115 | | |
114 | 116 | | |
| |||
131 | 133 | | |
132 | 134 | | |
133 | 135 | | |
| 136 | + | |
134 | 137 | | |
135 | 138 | | |
136 | 139 | | |
| |||
193 | 196 | | |
194 | 197 | | |
195 | 198 | | |
| 199 | + | |
196 | 200 | | |
197 | 201 | | |
198 | 202 | | |
199 | 203 | | |
200 | | - | |
| 204 | + | |
| 205 | + | |
201 | 206 | | |
202 | 207 | | |
203 | 208 | | |
| |||
0 commit comments