@@ -74,33 +74,33 @@ export const createOAuthMetadata = (options: {
7474 scopesSupported ?: string [ ] ;
7575} ) : OAuthMetadata => {
7676 const issuer = options . issuerUrl ;
77- const baseUrl = options . baseUrl ;
77+ const baseUrl = options . baseUrl || issuer ;
7878
7979 checkIssuerUrl ( issuer ) ;
8080
81- const authorization_endpoint = '/authorize' ;
82- const token_endpoint = '/token' ;
83- const registration_endpoint = options . provider . clientsStore . registerClient ? ' /register' : undefined ;
84- const revocation_endpoint = options . provider . revokeToken ? ' /revoke' : undefined ;
81+ const basePath = baseUrl . pathname . endsWith ( '/' ) ? baseUrl . pathname . slice ( 0 , - 1 ) : baseUrl . pathname ;
82+
83+ const registration_endpoint = options . provider . clientsStore . registerClient ? new URL ( ` ${ basePath } /register` , baseUrl ) . href : undefined ;
84+ const revocation_endpoint = options . provider . revokeToken ? new URL ( ` ${ basePath } /revoke` , baseUrl ) . href : undefined ;
8585
8686 const metadata : OAuthMetadata = {
8787 issuer : issuer . href ,
8888 service_documentation : options . serviceDocumentationUrl ?. href ,
8989
90- authorization_endpoint : new URL ( authorization_endpoint , baseUrl || issuer ) . href ,
90+ authorization_endpoint : new URL ( ` ${ basePath } /authorize` , baseUrl ) . href ,
9191 response_types_supported : [ 'code' ] ,
9292 code_challenge_methods_supported : [ 'S256' ] ,
9393
94- token_endpoint : new URL ( token_endpoint , baseUrl || issuer ) . href ,
94+ token_endpoint : new URL ( ` ${ basePath } /token` , baseUrl ) . href ,
9595 token_endpoint_auth_methods_supported : [ 'client_secret_post' ] ,
9696 grant_types_supported : [ 'authorization_code' , 'refresh_token' ] ,
9797
9898 scopes_supported : options . scopesSupported ,
9999
100- revocation_endpoint : revocation_endpoint ? new URL ( revocation_endpoint , baseUrl || issuer ) . href : undefined ,
100+ revocation_endpoint,
101101 revocation_endpoint_auth_methods_supported : revocation_endpoint ? [ 'client_secret_post' ] : undefined ,
102102
103- registration_endpoint : registration_endpoint ? new URL ( registration_endpoint , baseUrl || issuer ) . href : undefined
103+ registration_endpoint
104104 } ;
105105
106106 return metadata ;
@@ -133,6 +133,7 @@ export function mcpAuthRouter(options: AuthRouterOptions): RequestHandler {
133133 router . use (
134134 mcpAuthMetadataRouter ( {
135135 oauthMetadata,
136+ baseUrl : options . baseUrl ,
136137 // Prefer explicit RS; otherwise fall back to AS baseUrl, then to issuer (back-compat)
137138 resourceServerUrl : options . resourceServerUrl ?? options . baseUrl ?? new URL ( oauthMetadata . issuer ) ,
138139 serviceDocumentationUrl : options . serviceDocumentationUrl ,
@@ -168,6 +169,13 @@ export type AuthMetadataOptions = {
168169 */
169170 oauthMetadata : OAuthMetadata ;
170171
172+ /**
173+ * The base URL of the authorization server to use for the metadata endpoints.
174+ *
175+ * If not provided, the issuer URL will be used as the base URL.
176+ */
177+ baseUrl ?: URL ;
178+
171179 /**
172180 * The url of the MCP server, for use in protected resource metadata
173181 */
@@ -209,7 +217,8 @@ export function mcpAuthMetadataRouter(options: AuthMetadataOptions): express.Rou
209217 router . use ( `/.well-known/oauth-protected-resource${ rsPath === '/' ? '' : rsPath } ` , metadataHandler ( protectedResourceMetadata ) ) ;
210218
211219 // Always add this for OAuth Authorization Server metadata per RFC 8414
212- router . use ( '/.well-known/oauth-authorization-server' , metadataHandler ( options . oauthMetadata ) ) ;
220+ const asPath = new URL ( options . baseUrl || options . oauthMetadata . issuer ) . pathname ;
221+ router . use ( `/.well-known/oauth-authorization-server${ asPath === '/' ? '' : asPath } ` , metadataHandler ( options . oauthMetadata ) ) ;
213222
214223 return router ;
215224}
0 commit comments