@@ -2,7 +2,7 @@ import pkceChallenge from "pkce-challenge";
22import { LATEST_PROTOCOL_VERSION } from "../types.js" ;
33import type { OAuthClientMetadata , OAuthClientInformation , OAuthTokens , OAuthMetadata , OAuthClientInformationFull , OAuthProtectedResourceMetadata } from "../shared/auth.js" ;
44import { OAuthClientInformationFullSchema , OAuthMetadataSchema , OAuthProtectedResourceMetadataSchema , OAuthTokensSchema } from "../shared/auth.js" ;
5- import { resourceUrlFromServerUrl } from "../shared/auth-utils.js" ;
5+ import { checkResourceAllowed , resourceUrlFromServerUrl } from "../shared/auth-utils.js" ;
66
77/**
88 * Implements an end-to-end OAuth client to be used with one MCP server.
@@ -116,8 +116,8 @@ export async function auth(
116116 if ( resourceMetadata . authorization_servers && resourceMetadata . authorization_servers . length > 0 ) {
117117 authorizationServerUrl = resourceMetadata . authorization_servers [ 0 ] ;
118118 }
119- } catch ( error ) {
120- console . warn ( "Could not load OAuth Protected Resource metadata, falling back to /.well-known/oauth-authorization-server" , error )
119+ } catch {
120+ // Ignore errors and fall back to /.well-known/oauth-authorization-server
121121 }
122122
123123 const resource : URL | undefined = await selectResourceURL ( serverUrl , provider , resourceMetadata ) ;
@@ -175,8 +175,8 @@ export async function auth(
175175
176176 await provider . saveTokens ( newTokens ) ;
177177 return "AUTHORIZED" ;
178- } catch ( error ) {
179- console . error ( " Could not refresh OAuth tokens:" , error ) ;
178+ } catch {
179+ // Could not refresh OAuth tokens
180180 }
181181 }
182182
@@ -197,14 +197,17 @@ export async function auth(
197197 return "REDIRECT" ;
198198}
199199
200- async function selectResourceURL ( serverUrl : string | URL , provider : OAuthClientProvider , resourceMetadata ?: OAuthProtectedResourceMetadata ) : Promise < URL | undefined > {
200+ export async function selectResourceURL ( serverUrl : string | URL , provider : OAuthClientProvider , resourceMetadata ?: OAuthProtectedResourceMetadata ) : Promise < URL | undefined > {
201+ let resource = resourceUrlFromServerUrl ( serverUrl ) ;
201202 if ( provider . validateResourceURL ) {
202- return await provider . validateResourceURL ( serverUrl , resourceMetadata ?. resource ) ;
203- }
204-
205- const resource = resourceUrlFromServerUrl ( typeof serverUrl === "string" ? new URL ( serverUrl ) : serverUrl ) ;
206- if ( resourceMetadata && resourceMetadata . resource !== resource . href ) {
207- throw new Error ( `Protected resource ${ resourceMetadata . resource } does not match expected ${ resource } ` ) ;
203+ return await provider . validateResourceURL ( resource , resourceMetadata ?. resource ) ;
204+ } else if ( resourceMetadata ) {
205+ if ( checkResourceAllowed ( { requestedResource : resource , configuredResource : resourceMetadata . resource } ) ) {
206+ // If the resource mentioned in metadata is valid, prefer it since it is what the server is telling us to request.
207+ resource = new URL ( resourceMetadata . resource ) ;
208+ } else {
209+ throw new Error ( `Protected resource ${ resourceMetadata . resource } does not match expected ${ resource } (or origin)` ) ;
210+ }
208211 }
209212
210213 return resource ;
@@ -222,7 +225,6 @@ export function extractResourceMetadataUrl(res: Response): URL | undefined {
222225
223226 const [ type , scheme ] = authenticateHeader . split ( ' ' ) ;
224227 if ( type . toLowerCase ( ) !== 'bearer' || ! scheme ) {
225- console . log ( "Invalid WWW-Authenticate header format, expected 'Bearer'" ) ;
226228 return undefined ;
227229 }
228230 const regex = / r e s o u r c e _ m e t a d a t a = " ( [ ^ " ] * ) " / ;
@@ -235,7 +237,6 @@ export function extractResourceMetadataUrl(res: Response): URL | undefined {
235237 try {
236238 return new URL ( match [ 1 ] ) ;
237239 } catch {
238- console . log ( "Invalid resource metadata url: " , match [ 1 ] ) ;
239240 return undefined ;
240241 }
241242}
0 commit comments