@@ -78,7 +78,7 @@ export interface OAuthClientProvider {
78
78
*
79
79
* Implementations must verify the resource matches the MCP server.
80
80
*/
81
- validateProtectedResourceMetadata ? ( metadata ?: OAuthProtectedResourceMetadata ) : Promise < void > ;
81
+ validateResourceURL ? ( serverUrl : string | URL , resource ?: string ) : Promise < URL | undefined > ;
82
82
}
83
83
84
84
export type AuthResult = "AUTHORIZED" | "REDIRECT" ;
@@ -107,26 +107,19 @@ export async function auth(
107
107
scope ?: string ;
108
108
resourceMetadataUrl ?: URL } ) : Promise < AuthResult > {
109
109
110
- const resource = resourceUrlFromServerUrl ( typeof serverUrl === "string" ? new URL ( serverUrl ) : serverUrl ) ;
111
-
112
110
let resourceMetadata : OAuthProtectedResourceMetadata | undefined ;
113
111
let authorizationServerUrl = serverUrl ;
114
112
try {
115
113
resourceMetadata = await discoverOAuthProtectedResourceMetadata ( serverUrl , { resourceMetadataUrl} ) ;
116
- } catch ( error ) {
117
- console . warn ( "Could not load OAuth Protected Resource metadata, falling back to /.well-known/oauth-authorization-server" , error )
118
- }
119
- if ( provider . validateProtectedResourceMetadata ) {
120
- await provider . validateProtectedResourceMetadata ( resourceMetadata ) ;
121
- } else if ( resourceMetadata ) {
122
114
if ( resourceMetadata . authorization_servers && resourceMetadata . authorization_servers . length > 0 ) {
123
115
authorizationServerUrl = resourceMetadata . authorization_servers [ 0 ] ;
124
116
}
125
- if ( resourceMetadata . resource !== resource . href ) {
126
- throw new Error ( `Protected resource ${ resourceMetadata . resource } does not match expected ${ resource } ` ) ;
127
- }
117
+ } catch ( error ) {
118
+ console . warn ( "Could not load OAuth Protected Resource metadata, falling back to /.well-known/oauth-authorization-server" , error )
128
119
}
129
120
121
+ const resource : URL | undefined = await selectResourceURL ( serverUrl , provider , resourceMetadata ) ;
122
+
130
123
const metadata = await discoverOAuthMetadata ( authorizationServerUrl ) ;
131
124
132
125
// Handle client registration if needed
@@ -202,6 +195,19 @@ export async function auth(
202
195
return "REDIRECT" ;
203
196
}
204
197
198
+ async function selectResourceURL ( serverUrl : string | URL , provider : OAuthClientProvider , resourceMetadata ?: OAuthProtectedResourceMetadata ) : Promise < URL | undefined > {
199
+ if ( provider . validateResourceURL ) {
200
+ return await provider . validateResourceURL ( serverUrl , resourceMetadata ?. resource ) ;
201
+ }
202
+
203
+ const resource = resourceUrlFromServerUrl ( typeof serverUrl === "string" ? new URL ( serverUrl ) : serverUrl ) ;
204
+ if ( resourceMetadata && resourceMetadata . resource !== resource . href ) {
205
+ throw new Error ( `Protected resource ${ resourceMetadata . resource } does not match expected ${ resource } ` ) ;
206
+ }
207
+
208
+ return resource ;
209
+ }
210
+
205
211
/**
206
212
* Extract resource_metadata from response header.
207
213
*/
0 commit comments