@@ -5,7 +5,6 @@ import { OAuthClientInformationFull, OAuthMetadata, OAuthTokens } from '../../sh
5
5
import express , { Request , Response } from "express" ;
6
6
import { AuthInfo } from '../../server/auth/types.js' ;
7
7
import { createOAuthMetadata , mcpAuthRouter } from '../../server/auth/router.js' ;
8
- import { InvalidTargetError , InvalidRequestError } from '../../server/auth/errors.js' ;
9
8
import { resourceUrlFromServerUrl } from '../../shared/auth-utils.js' ;
10
9
11
10
@@ -22,61 +21,28 @@ export class DemoInMemoryClientsStore implements OAuthRegisteredClientsStore {
22
21
}
23
22
}
24
23
25
- /**
26
- * Configuration options for the demo OAuth provider
27
- */
28
- export interface DemoOAuthProviderConfig {
29
- /**
30
- * The canonical URL of this MCP server. When provided, the provider will validate
31
- * that the resource parameter in OAuth requests matches this URL.
32
- *
33
- * This should be the full URL that clients use to connect to this server,
34
- * without any fragment component (e.g., "https://api.example.com/mcp").
35
- *
36
- * Required when validateResourceMatchesServer is true.
37
- */
38
- serverUrl ?: string ;
39
-
40
- /**
41
- * If true, validates that the resource parameter matches the configured serverUrl.
42
- *
43
- * When enabled:
44
- * - serverUrl must be configured (throws error if not)
45
- * - resource parameter is required on all requests
46
- * - resource must exactly match serverUrl (after fragment removal)
47
- * - requests without resource parameter will be rejected with invalid_request error
48
- * - requests with non-matching resource will be rejected with invalid_target error
49
- *
50
- * When disabled:
51
- * - warnings are logged when resource parameter is missing (for migration tracking)
52
- *
53
- * @default false
54
- */
55
- validateResourceMatchesServer ?: boolean ;
56
- }
57
-
58
24
export class DemoInMemoryAuthProvider implements OAuthServerProvider {
59
25
clientsStore = new DemoInMemoryClientsStore ( ) ;
60
26
private codes = new Map < string , {
61
27
params : AuthorizationParams ,
62
28
client : OAuthClientInformationFull } > ( ) ;
63
29
private tokens = new Map < string , AuthInfo > ( ) ;
64
- private config ?: DemoOAuthProviderConfig ;
65
-
66
- constructor ( config ?: DemoOAuthProviderConfig ) {
67
- if ( config ?. validateResourceMatchesServer && ! config ?. serverUrl ) {
68
- throw new Error ( "serverUrl must be configured when validateResourceMatchesServer is true" ) ;
30
+ private validateResource ?: ( resource ?: URL ) => boolean ;
31
+
32
+ constructor ( mcpServerUrl ?: URL ) {
33
+ if ( mcpServerUrl ) {
34
+ const expectedResource = resourceUrlFromServerUrl ( mcpServerUrl ) ;
35
+ this . validateResource = ( resource ?: URL ) => {
36
+ return ! resource || resource . toString ( ) !== expectedResource . toString ( ) ;
37
+ } ;
69
38
}
70
- this . config = config ;
71
39
}
72
40
73
41
async authorize (
74
42
client : OAuthClientInformationFull ,
75
43
params : AuthorizationParams ,
76
44
res : Response
77
45
) : Promise < void > {
78
- await this . validateResource ( params . resource ) ;
79
-
80
46
const code = randomUUID ( ) ;
81
47
82
48
const searchParams = new URLSearchParams ( {
@@ -126,7 +92,9 @@ export class DemoInMemoryAuthProvider implements OAuthServerProvider {
126
92
throw new Error ( `Authorization code was not issued to this client, ${ codeData . client . client_id } != ${ client . client_id } ` ) ;
127
93
}
128
94
129
- await this . validateResource ( codeData . params . resource ) ;
95
+ if ( this . validateResource && ! this . validateResource ( codeData . params . resource ) ) {
96
+ throw new Error ( 'Invalid resource' ) ;
97
+ }
130
98
131
99
this . codes . delete ( authorizationCode ) ;
132
100
const token = randomUUID ( ) ;
@@ -164,7 +132,6 @@ export class DemoInMemoryAuthProvider implements OAuthServerProvider {
164
132
if ( ! tokenData || ! tokenData . expiresAt || tokenData . expiresAt < Date . now ( ) ) {
165
133
throw new Error ( 'Invalid or expired token' ) ;
166
134
}
167
- await this . validateResource ( tokenData . resource ) ;
168
135
169
136
return {
170
137
token,
@@ -175,29 +142,6 @@ export class DemoInMemoryAuthProvider implements OAuthServerProvider {
175
142
} ;
176
143
}
177
144
178
- /**
179
- * Validates that the client is allowed to access the requested resource.
180
- * In a real implementation, this would check against a database or configuration.
181
- */
182
- private async validateResource ( resource ?: string ) : Promise < void > {
183
- if ( this . config ?. validateResourceMatchesServer ) {
184
- if ( ! resource ) {
185
- throw new InvalidRequestError ( "Resource parameter is required when server URL validation is enabled" ) ;
186
- }
187
-
188
- const canonicalServerUrl = resourceUrlFromServerUrl ( this . config . serverUrl ! ) ;
189
-
190
- if ( resource !== canonicalServerUrl ) {
191
- throw new InvalidTargetError (
192
- `Resource parameter '${ resource } ' does not match this server's URL '${ canonicalServerUrl } '`
193
- ) ;
194
- }
195
- } else if ( ! resource ) {
196
- // Always log warning if resource is missing (unless validation is enabled)
197
- console . warn ( `Token refresh request is missing the resource parameter. Consider migrating to RFC 8707.` ) ;
198
- }
199
- }
200
-
201
145
/**
202
146
* Get token details including resource information (for demo introspection endpoint)
203
147
*/
@@ -207,13 +151,13 @@ export class DemoInMemoryAuthProvider implements OAuthServerProvider {
207
151
}
208
152
209
153
210
- export const setupAuthServer = ( authServerUrl : URL , config ?: DemoOAuthProviderConfig ) : OAuthMetadata => {
154
+ export const setupAuthServer = ( authServerUrl : URL , mcpServerUrl : URL ) : OAuthMetadata => {
211
155
// Create separate auth server app
212
156
// NOTE: This is a separate app on a separate port to illustrate
213
157
// how to separate an OAuth Authorization Server from a Resource
214
158
// server in the SDK. The SDK is not intended to be provide a standalone
215
159
// authorization server.
216
- const provider = new DemoInMemoryAuthProvider ( config ) ;
160
+ const provider = new DemoInMemoryAuthProvider ( mcpServerUrl ) ;
217
161
const authApp = express ( ) ;
218
162
authApp . use ( express . json ( ) ) ;
219
163
// For introspection requests
0 commit comments