Skip to content

Commit f854b58

Browse files
committed
test validateProtectedResourceMetadata override
1 parent 4b3db9b commit f854b58

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/client/auth.test.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,5 +983,66 @@ describe("OAuth Authorization", () => {
983983
expect(body.get("grant_type")).toBe("refresh_token");
984984
expect(body.get("refresh_token")).toBe("refresh123");
985985
});
986+
987+
it("skips default PRM resource validation when custom validateProtectedResourceMetadata is provided", async () => {
988+
const mockValidateProtectedResourceMetadata = jest.fn().mockResolvedValue(undefined);
989+
const providerWithCustomValidation = {
990+
...mockProvider,
991+
validateProtectedResourceMetadata: mockValidateProtectedResourceMetadata,
992+
};
993+
994+
// Mock protected resource metadata with mismatched resource URL
995+
// This would normally throw an error in default validation, but should be skipped
996+
mockFetch.mockImplementation((url) => {
997+
const urlString = url.toString();
998+
999+
if (urlString.includes("/.well-known/oauth-protected-resource")) {
1000+
return Promise.resolve({
1001+
ok: true,
1002+
status: 200,
1003+
json: async () => ({
1004+
resource: "https://different-resource.example.com/mcp-server", // Mismatched resource
1005+
authorization_servers: ["https://auth.example.com"],
1006+
}),
1007+
});
1008+
} else if (urlString.includes("/.well-known/oauth-authorization-server")) {
1009+
return Promise.resolve({
1010+
ok: true,
1011+
status: 200,
1012+
json: async () => ({
1013+
issuer: "https://auth.example.com",
1014+
authorization_endpoint: "https://auth.example.com/authorize",
1015+
token_endpoint: "https://auth.example.com/token",
1016+
response_types_supported: ["code"],
1017+
code_challenge_methods_supported: ["S256"],
1018+
}),
1019+
});
1020+
}
1021+
1022+
return Promise.resolve({ ok: false, status: 404 });
1023+
});
1024+
1025+
// Mock provider methods
1026+
(providerWithCustomValidation.clientInformation as jest.Mock).mockResolvedValue({
1027+
client_id: "test-client",
1028+
client_secret: "test-secret",
1029+
});
1030+
(providerWithCustomValidation.tokens as jest.Mock).mockResolvedValue(undefined);
1031+
(providerWithCustomValidation.saveCodeVerifier as jest.Mock).mockResolvedValue(undefined);
1032+
(providerWithCustomValidation.redirectToAuthorization as jest.Mock).mockResolvedValue(undefined);
1033+
1034+
// Call auth - should succeed despite resource mismatch because custom validation overrides default
1035+
const result = await auth(providerWithCustomValidation, {
1036+
serverUrl: "https://api.example.com/mcp-server",
1037+
});
1038+
1039+
expect(result).toBe("REDIRECT");
1040+
1041+
// Verify custom validation method was called
1042+
expect(mockValidateProtectedResourceMetadata).toHaveBeenCalledWith({
1043+
resource: "https://different-resource.example.com/mcp-server",
1044+
authorization_servers: ["https://auth.example.com"],
1045+
});
1046+
});
9861047
});
9871048
});

src/client/auth.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export interface OAuthClientProvider {
7676
/**
7777
* If defined, overrides the OAuth Protected Resource Metadata (RFC 9728).
7878
*
79-
* Implementations must verify the provider
79+
* Implementations must verify the resource matches the MCP server.
8080
*/
8181
validateProtectedResourceMetadata?(metadata?: OAuthProtectedResourceMetadata): Promise<void>;
8282
}

0 commit comments

Comments
 (0)