Skip to content

Commit 551a439

Browse files
committed
use URL for resource throughout
1 parent 224a2e2 commit 551a439

File tree

7 files changed

+31
-31
lines changed

7 files changed

+31
-31
lines changed

src/client/auth.test.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ describe("OAuth Authorization", () => {
347347
{
348348
clientInformation: validClientInfo,
349349
redirectUrl: "http://localhost:3000/callback",
350-
resource: "https://api.example.com/mcp-server",
350+
resource: new URL("https://api.example.com/mcp-server"),
351351
}
352352
);
353353

@@ -526,7 +526,7 @@ describe("OAuth Authorization", () => {
526526
authorizationCode: "code123",
527527
codeVerifier: "verifier123",
528528
redirectUri: "http://localhost:3000/callback",
529-
resource: "https://api.example.com/mcp-server",
529+
resource: new URL("https://api.example.com/mcp-server"),
530530
});
531531

532532
expect(tokens).toEqual(validTokens);
@@ -650,7 +650,7 @@ describe("OAuth Authorization", () => {
650650
const tokens = await refreshAuthorization("https://auth.example.com", {
651651
clientInformation: validClientInfo,
652652
refreshToken: "refresh123",
653-
resource: "https://api.example.com/mcp-server",
653+
resource: new URL("https://api.example.com/mcp-server"),
654654
});
655655

656656
expect(tokens).toEqual(validTokensWithNewRefreshToken);
@@ -939,7 +939,7 @@ describe("OAuth Authorization", () => {
939939
// Call the auth function with a resource that has a fragment
940940
const result = await auth(mockProvider, {
941941
serverUrl: "https://resource.example.com",
942-
resource: "https://api.example.com/mcp-server#fragment",
942+
resource: new URL("https://api.example.com/mcp-server#fragment"),
943943
});
944944

945945
expect(result).toBe("REDIRECT");
@@ -988,7 +988,7 @@ describe("OAuth Authorization", () => {
988988
// Call auth without authorization code (should trigger redirect)
989989
const result = await auth(mockProvider, {
990990
serverUrl: "https://resource.example.com",
991-
resource: "https://api.example.com/mcp-server",
991+
resource: new URL("https://api.example.com/mcp-server"),
992992
});
993993

994994
expect(result).toBe("REDIRECT");
@@ -1050,7 +1050,7 @@ describe("OAuth Authorization", () => {
10501050
const result = await auth(mockProvider, {
10511051
serverUrl: "https://resource.example.com",
10521052
authorizationCode: "auth-code-123",
1053-
resource: "https://api.example.com/mcp-server",
1053+
resource: new URL("https://api.example.com/mcp-server"),
10541054
});
10551055

10561056
expect(result).toBe("AUTHORIZED");
@@ -1112,7 +1112,7 @@ describe("OAuth Authorization", () => {
11121112
// Call auth with existing tokens (should trigger refresh)
11131113
const result = await auth(mockProvider, {
11141114
serverUrl: "https://resource.example.com",
1115-
resource: "https://api.example.com/mcp-server",
1115+
resource: new URL("https://api.example.com/mcp-server"),
11161116
});
11171117

11181118
expect(result).toBe("AUTHORIZED");
@@ -1161,7 +1161,7 @@ describe("OAuth Authorization", () => {
11611161
// Call auth with empty resource parameter
11621162
const result = await auth(mockProvider, {
11631163
serverUrl: "https://resource.example.com",
1164-
resource: "",
1164+
resource: undefined,
11651165
});
11661166

11671167
expect(result).toBe("REDIRECT");
@@ -1204,7 +1204,7 @@ describe("OAuth Authorization", () => {
12041204
// Call auth with resource containing multiple # symbols
12051205
const result = await auth(mockProvider, {
12061206
serverUrl: "https://resource.example.com",
1207-
resource: "https://api.example.com/mcp-server#fragment#another",
1207+
resource: new URL("https://api.example.com/mcp-server#fragment#another"),
12081208
});
12091209

12101210
expect(result).toBe("REDIRECT");
@@ -1249,7 +1249,7 @@ describe("OAuth Authorization", () => {
12491249
// multiple MCP servers on the same domain
12501250
const result1 = await auth(mockProvider, {
12511251
serverUrl: "https://api.example.com",
1252-
resource: "https://api.example.com/mcp-server-1/v1",
1252+
resource: new URL("https://api.example.com/mcp-server-1/v1"),
12531253
});
12541254

12551255
expect(result1).toBe("REDIRECT");
@@ -1264,7 +1264,7 @@ describe("OAuth Authorization", () => {
12641264
// Test with different path on same domain
12651265
const result2 = await auth(mockProvider, {
12661266
serverUrl: "https://api.example.com",
1267-
resource: "https://api.example.com/mcp-server-2/v1",
1267+
resource: new URL("https://api.example.com/mcp-server-2/v1"),
12681268
});
12691269

12701270
expect(result2).toBe("REDIRECT");
@@ -1309,7 +1309,7 @@ describe("OAuth Authorization", () => {
13091309
// Call auth with resource containing query parameters
13101310
const result = await auth(mockProvider, {
13111311
serverUrl: "https://resource.example.com",
1312-
resource: "https://api.example.com/mcp-server?param=value&another=test",
1312+
resource: new URL("https://api.example.com/mcp-server?param=value&another=test"),
13131313
});
13141314

13151315
expect(result).toBe("REDIRECT");

src/client/sse.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { EventSource, type ErrorEvent, type EventSourceInit } from "eventsource"
22
import { Transport } from "../shared/transport.js";
33
import { JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
44
import { auth, AuthResult, extractResourceMetadataUrl, OAuthClientProvider, UnauthorizedError } from "./auth.js";
5-
import { extractResourceUri } from "../shared/auth-utils.js";
5+
import { resourceUrlFromServerUrl } from "../shared/auth-utils.js";
66

77
export class SseError extends Error {
88
constructor(
@@ -90,7 +90,7 @@ export class SSEClientTransport implements Transport {
9090
result = await auth(this._authProvider, {
9191
serverUrl: this._url,
9292
resourceMetadataUrl: this._resourceMetadataUrl,
93-
resource: extractResourceUri(this._url)
93+
resource: resourceUrlFromServerUrl(new URL(this._url))
9494
});
9595
} catch (error) {
9696
this.onerror?.(error as Error);
@@ -210,7 +210,7 @@ export class SSEClientTransport implements Transport {
210210
serverUrl: this._url,
211211
authorizationCode,
212212
resourceMetadataUrl: this._resourceMetadataUrl,
213-
resource: extractResourceUri(this._url)
213+
resource: resourceUrlFromServerUrl(new URL(this._url))
214214
});
215215
if (result !== "AUTHORIZED") {
216216
throw new UnauthorizedError("Failed to authorize");
@@ -249,7 +249,7 @@ export class SSEClientTransport implements Transport {
249249
const result = await auth(this._authProvider, {
250250
serverUrl: this._url,
251251
resourceMetadataUrl: this._resourceMetadataUrl,
252-
resource: extractResourceUri(this._url)
252+
resource: resourceUrlFromServerUrl(new URL(this._url))
253253
});
254254
if (result !== "AUTHORIZED") {
255255
throw new UnauthorizedError();

src/client/streamableHttp.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Transport } from "../shared/transport.js";
22
import { isInitializedNotification, isJSONRPCRequest, isJSONRPCResponse, JSONRPCMessage, JSONRPCMessageSchema } from "../types.js";
33
import { auth, AuthResult, extractResourceMetadataUrl, OAuthClientProvider, UnauthorizedError } from "./auth.js";
44
import { EventSourceParserStream } from "eventsource-parser/stream";
5-
import { extractResourceUri } from "../shared/auth-utils.js";
5+
import { resourceUrlFromServerUrl } from "../shared/auth-utils.js";
66

77
// Default reconnection options for StreamableHTTP connections
88
const DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS: StreamableHTTPReconnectionOptions = {
@@ -153,7 +153,7 @@ export class StreamableHTTPClientTransport implements Transport {
153153
result = await auth(this._authProvider, {
154154
serverUrl: this._url,
155155
resourceMetadataUrl: this._resourceMetadataUrl,
156-
resource: extractResourceUri(this._url)
156+
resource: resourceUrlFromServerUrl(new URL(this._url))
157157
});
158158
} catch (error) {
159159
this.onerror?.(error as Error);
@@ -371,7 +371,7 @@ export class StreamableHTTPClientTransport implements Transport {
371371
serverUrl: this._url,
372372
authorizationCode,
373373
resourceMetadataUrl: this._resourceMetadataUrl,
374-
resource: extractResourceUri(this._url)
374+
resource: resourceUrlFromServerUrl(new URL(this._url))
375375
});
376376
if (result !== "AUTHORIZED") {
377377
throw new UnauthorizedError("Failed to authorize");
@@ -423,7 +423,7 @@ export class StreamableHTTPClientTransport implements Transport {
423423
const result = await auth(this._authProvider, {
424424
serverUrl: this._url,
425425
resourceMetadataUrl: this._resourceMetadataUrl,
426-
resource: extractResourceUri(this._url)
426+
resource: resourceUrlFromServerUrl(new URL(this._url))
427427
});
428428
if (result !== "AUTHORIZED") {
429429
throw new UnauthorizedError();

src/server/auth/handlers/token.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ describe('Token Handler', () => {
303303
'valid_code',
304304
undefined, // code_verifier is undefined after PKCE validation
305305
undefined, // redirect_uri
306-
'https://api.example.com/resource' // resource parameter
306+
new URL('https://api.example.com/resource') // resource parameter
307307
);
308308
});
309309

@@ -371,7 +371,7 @@ describe('Token Handler', () => {
371371
'valid_code',
372372
undefined, // code_verifier is undefined after PKCE validation
373373
'https://example.com/callback', // redirect_uri
374-
'https://api.example.com/resource' // resource parameter
374+
new URL('https://api.example.com/resource') // resource parameter
375375
);
376376
});
377377

@@ -585,7 +585,7 @@ describe('Token Handler', () => {
585585
validClient,
586586
'valid_refresh_token',
587587
undefined, // scopes
588-
'https://api.example.com/resource' // resource parameter
588+
new URL('https://api.example.com/resource') // resource parameter
589589
);
590590
});
591591

@@ -648,7 +648,7 @@ describe('Token Handler', () => {
648648
validClient,
649649
'valid_refresh_token',
650650
['profile', 'email'], // scopes
651-
'https://api.example.com/resource' // resource parameter
651+
new URL('https://api.example.com/resource') // resource parameter
652652
);
653653
});
654654
});

src/server/auth/handlers/token.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export function tokenHandler({ provider, rateLimit: rateLimitConfig }: TokenHand
113113
code,
114114
skipLocalPkceValidation ? code_verifier : undefined,
115115
redirect_uri,
116-
resource
116+
resource ? new URL(resource) : undefined
117117
);
118118
res.status(200).json(tokens);
119119
break;
@@ -131,7 +131,7 @@ export function tokenHandler({ provider, rateLimit: rateLimitConfig }: TokenHand
131131
// The provider can decide how to validate it
132132

133133
const scopes = scope?.split(" ");
134-
const tokens = await provider.exchangeRefreshToken(client, refresh_token, scopes, resource);
134+
const tokens = await provider.exchangeRefreshToken(client, refresh_token, scopes, resource ? new URL(resource) : undefined);
135135
res.status(200).json(tokens);
136136
break;
137137
}

src/server/auth/providers/proxyProvider.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ describe("Proxy OAuth Server Provider", () => {
213213
'test-code',
214214
'test-verifier',
215215
'https://example.com/callback',
216-
'https://api.example.com/resource'
216+
new URL('https://api.example.com/resource')
217217
);
218218

219219
expect(global.fetch).toHaveBeenCalledWith(
@@ -267,7 +267,7 @@ describe("Proxy OAuth Server Provider", () => {
267267
validClient,
268268
'test-refresh-token',
269269
['read', 'write'],
270-
'https://api.example.com/resource'
270+
new URL('https://api.example.com/resource')
271271
);
272272

273273
expect(global.fetch).toHaveBeenCalledWith(
@@ -301,7 +301,7 @@ describe("Proxy OAuth Server Provider", () => {
301301
validClient,
302302
'test-refresh-token',
303303
['profile', 'email'],
304-
'https://api.example.com/resource'
304+
new URL('https://api.example.com/resource')
305305
);
306306

307307
const fetchCall = (global.fetch as jest.Mock).mock.calls[0];

src/server/auth/providers/proxyProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export class ProxyOAuthServerProvider implements OAuthServerProvider {
175175
}
176176

177177
if (resource) {
178-
params.append("resource", resource);
178+
params.append("resource", resource.href);
179179
}
180180

181181
const response = await fetch(this._endpoints.tokenUrl, {
@@ -217,7 +217,7 @@ export class ProxyOAuthServerProvider implements OAuthServerProvider {
217217
}
218218

219219
if (resource) {
220-
params.set("resource", resource);
220+
params.set("resource", resource.href);
221221
}
222222

223223
const response = await fetch(this._endpoints.tokenUrl, {

0 commit comments

Comments
 (0)