@@ -49,6 +49,7 @@ import Testing
4949
5050 let metadata = try await makeClient ( ) . fetchProtectedResourceMetadata (
5151 candidates: [ URL ( string: " https://example.com/.well-known/oauth-protected-resource " ) !] ,
52+ fallbackIssuer: nil ,
5253 session: session
5354 )
5455 let expected = OAuthProtectedResourceMetadata (
@@ -76,6 +77,7 @@ import Testing
7677 URL ( string: " https://example.com/.well-known/oauth-protected-resource/mcp " ) !,
7778 URL ( string: " https://example.com/.well-known/oauth-protected-resource " ) !,
7879 ] ,
80+ fallbackIssuer: nil ,
7981 session: session
8082 )
8183 let expected = OAuthProtectedResourceMetadata (
@@ -103,6 +105,7 @@ import Testing
103105 URL ( string: " https://example.com/.well-known/oauth-protected-resource/mcp " ) !,
104106 URL ( string: " https://example.com/.well-known/oauth-protected-resource " ) !,
105107 ] ,
108+ fallbackIssuer: nil ,
106109 session: session
107110 )
108111 let expected = OAuthProtectedResourceMetadata (
@@ -112,7 +115,7 @@ import Testing
112115 #expect( metadata == expected)
113116 }
114117
115- @Test ( " Throws metadataDiscoveryFailed when all candidates fail " )
118+ @Test ( " Throws metadataDiscoveryFailed when all candidates fail and no fallback issuer " )
116119 func testFetchProtectedResourceMetadataThrowsWhenAllFail( ) async throws {
117120 let ( session, key) = makeIsolatedSession ( )
118121 await IsolatedMockURLProtocol . setHandler ( key: key) { request in
@@ -126,11 +129,34 @@ import Testing
126129 candidates: [
127130 URL ( string: " https://example.com/.well-known/oauth-protected-resource " ) !
128131 ] ,
132+ fallbackIssuer: nil ,
129133 session: session
130134 )
131135 }
132136 }
133137
138+ @Test ( " Returns synthetic metadata with fallback issuer when all candidates fail " )
139+ func testFetchProtectedResourceMetadataUsesFallbackIssuer( ) async throws {
140+ let fallback = URL ( string: " https://example.com " ) !
141+ let ( session, key) = makeIsolatedSession ( )
142+ await IsolatedMockURLProtocol . setHandler ( key: key) { request in
143+ let response = HTTPURLResponse (
144+ url: request. url!, statusCode: 404 , httpVersion: nil , headerFields: nil ) !
145+ return ( response, Data ( ) )
146+ }
147+
148+ let metadata = try await makeClient ( ) . fetchProtectedResourceMetadata (
149+ candidates: [ URL ( string: " https://example.com/.well-known/oauth-protected-resource " ) !] ,
150+ fallbackIssuer: fallback,
151+ session: session
152+ )
153+ let expected = OAuthProtectedResourceMetadata (
154+ resource: nil ,
155+ authorizationServers: [ fallback] ,
156+ scopesSupported: nil )
157+ #expect( metadata == expected)
158+ }
159+
134160 // MARK: - fetchAuthorizationServerMetadata
135161
136162 @Test ( " Returns server and metadata when issuer matches " )
@@ -162,23 +188,23 @@ import Testing
162188 #expect( metadata == expectedMetadata)
163189 }
164190
165- @Test ( " Skips candidate when issuer field does not match " )
166- func testFetchAuthorizationServerMetadataSkipsIssuerMismatch( ) async throws {
167- let wrongIssuerBody = try makeASMetadataBody ( issuer: " https://other.example.com " )
191+ @Test ( " Uses metadata issuer as server identity when it differs from candidate URL " )
192+ func testFetchAuthorizationServerMetadataUsesMetadataIssuer( ) async throws {
193+ let metadataIssuer = " https://other.example.com "
194+ let body = try makeASMetadataBody ( issuer: metadataIssuer)
168195 let ( session, key) = makeIsolatedSession ( )
169196 await IsolatedMockURLProtocol . setHandler ( key: key) { _ in
170197 let response = HTTPURLResponse (
171198 url: URL ( string: " https://auth.example.com " ) !,
172199 statusCode: 200 , httpVersion: nil , headerFields: nil ) !
173- return ( response, wrongIssuerBody )
200+ return ( response, body )
174201 }
175202
176- await #expect( throws: OAuthAuthorizationError . self) {
177- try await makeClient ( ) . fetchAuthorizationServerMetadata (
178- candidates: [ URL ( string: " https://auth.example.com " ) !] ,
179- session: session
180- )
181- }
203+ let ( server, _) = try await makeClient ( ) . fetchAuthorizationServerMetadata (
204+ candidates: [ URL ( string: " https://auth.example.com " ) !] ,
205+ session: session
206+ )
207+ #expect( server == URL ( string: metadataIssuer) !)
182208 }
183209
184210 @Test ( " Skips private IP candidates without making HTTP calls " )
0 commit comments