Skip to content

Commit c6fad3f

Browse files
authored
fix: quick oauth flow could not transition to token_request due to missing server metadata (#407)
* fix: quick oauth flow could not transition to token_request due to missing server metadata * chore: prettier fix
1 parent 05e41d2 commit c6fad3f

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

client/src/components/AuthDebugger.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { useCallback, useMemo } from "react";
22
import { Button } from "@/components/ui/button";
33
import { DebugInspectorOAuthClientProvider } from "../lib/auth";
4-
import { auth } from "@modelcontextprotocol/sdk/client/auth.js";
4+
import {
5+
auth,
6+
discoverOAuthMetadata,
7+
} from "@modelcontextprotocol/sdk/client/auth.js";
8+
import { OAuthMetadataSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
59
import { AlertCircle } from "lucide-react";
610
import { AuthDebuggerState } from "../lib/auth-types";
711
import { OAuthFlowProgress } from "./OAuthFlowProgress";
@@ -123,6 +127,14 @@ const AuthDebugger = ({
123127
const serverAuthProvider = new DebugInspectorOAuthClientProvider(
124128
serverUrl,
125129
);
130+
// First discover OAuth metadata separately so we can save it
131+
const metadata = await discoverOAuthMetadata(serverUrl);
132+
if (!metadata) {
133+
throw new Error("Failed to discover OAuth metadata");
134+
}
135+
const parsedMetadata = await OAuthMetadataSchema.parseAsync(metadata);
136+
serverAuthProvider.saveServerMetadata(parsedMetadata);
137+
126138
await auth(serverAuthProvider, { serverUrl: serverUrl });
127139
updateAuthState({
128140
statusMessage: {

client/src/components/__tests__/AuthDebugger.test.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
registerClient,
4949
startAuthorization,
5050
exchangeAuthorization,
51+
auth,
5152
} from "@modelcontextprotocol/sdk/client/auth.js";
5253
import { OAuthMetadata } from "@modelcontextprotocol/sdk/shared/auth.js";
5354

@@ -64,6 +65,7 @@ const mockStartAuthorization = startAuthorization as jest.MockedFunction<
6465
const mockExchangeAuthorization = exchangeAuthorization as jest.MockedFunction<
6566
typeof exchangeAuthorization
6667
>;
68+
const mockAuth = auth as jest.MockedFunction<typeof auth>;
6769

6870
const sessionStorageMock = {
6971
getItem: jest.fn(),
@@ -186,6 +188,63 @@ describe("AuthDebugger", () => {
186188
},
187189
});
188190
});
191+
192+
it("should start quick OAuth flow and properly fetch and save metadata", async () => {
193+
// Setup the auth mock
194+
mockAuth.mockResolvedValue("AUTHORIZED");
195+
196+
const updateAuthState = jest.fn();
197+
await act(async () => {
198+
renderAuthDebugger({ updateAuthState });
199+
});
200+
201+
await act(async () => {
202+
fireEvent.click(screen.getByText("Quick OAuth Flow"));
203+
});
204+
205+
// Should first discover and save OAuth metadata
206+
expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith(
207+
"https://example.com",
208+
);
209+
210+
// Then should call auth with the server provider
211+
expect(mockAuth).toHaveBeenCalled();
212+
213+
// Check that updateAuthState was called with the right info message
214+
expect(updateAuthState).toHaveBeenCalledWith(
215+
expect.objectContaining({
216+
statusMessage: {
217+
type: "info",
218+
message: "Starting OAuth authentication process...",
219+
},
220+
}),
221+
);
222+
});
223+
224+
it("should show error when quick OAuth flow fails to discover metadata", async () => {
225+
mockDiscoverOAuthMetadata.mockRejectedValue(
226+
new Error("Metadata discovery failed"),
227+
);
228+
229+
const updateAuthState = jest.fn();
230+
await act(async () => {
231+
renderAuthDebugger({ updateAuthState });
232+
});
233+
234+
await act(async () => {
235+
fireEvent.click(screen.getByText("Quick OAuth Flow"));
236+
});
237+
238+
// Check that updateAuthState was called with an error message
239+
expect(updateAuthState).toHaveBeenCalledWith(
240+
expect.objectContaining({
241+
statusMessage: {
242+
type: "error",
243+
message: expect.stringContaining("Failed to start OAuth flow"),
244+
},
245+
}),
246+
);
247+
});
189248
});
190249

191250
describe("Session Storage Integration", () => {

0 commit comments

Comments
 (0)