rm loading, prm test
This commit is contained in:
parent
cc49358f5a
commit
03bb303bf9
4 changed files with 131 additions and 22 deletions
|
|
@ -329,8 +329,6 @@ const App = () => {
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading OAuth tokens:", error);
|
console.error("Error loading OAuth tokens:", error);
|
||||||
} finally {
|
|
||||||
updateAuthState({ loading: false });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,23 +60,23 @@ const AuthDebugger = ({
|
||||||
authState,
|
authState,
|
||||||
updateAuthState,
|
updateAuthState,
|
||||||
}: AuthDebuggerProps) => {
|
}: AuthDebuggerProps) => {
|
||||||
// Initialize loading state
|
// Check for existing tokens on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (authState.loading && serverUrl) {
|
if (serverUrl && !authState.oauthTokens) {
|
||||||
// Check if we have existing tokens
|
|
||||||
const checkTokens = async () => {
|
const checkTokens = async () => {
|
||||||
const provider = new DebugInspectorOAuthClientProvider(serverUrl);
|
const provider = new DebugInspectorOAuthClientProvider(serverUrl);
|
||||||
const existingTokens = await provider.tokens();
|
const existingTokens = await provider.tokens();
|
||||||
|
if (existingTokens) {
|
||||||
updateAuthState({
|
updateAuthState({
|
||||||
loading: false,
|
oauthTokens: existingTokens,
|
||||||
oauthTokens: existingTokens || null,
|
oauthStep: "complete",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
checkTokens();
|
checkTokens();
|
||||||
}
|
}
|
||||||
}, [serverUrl, authState.loading, updateAuthState]);
|
}, [serverUrl]); // Only run when serverUrl changes
|
||||||
|
|
||||||
const startOAuthFlow = useCallback(() => {
|
const startOAuthFlow = useCallback(() => {
|
||||||
if (!serverUrl) {
|
if (!serverUrl) {
|
||||||
updateAuthState({
|
updateAuthState({
|
||||||
|
|
@ -241,10 +241,7 @@ const AuthDebugger = ({
|
||||||
<StatusMessage message={authState.statusMessage} />
|
<StatusMessage message={authState.statusMessage} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{authState.loading ? (
|
<div className="space-y-4">
|
||||||
<p>Loading authentication status...</p>
|
|
||||||
) : (
|
|
||||||
<div className="space-y-4">
|
|
||||||
{authState.oauthTokens && (
|
{authState.oauthTokens && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<p className="text-sm font-medium">Access Token:</p>
|
<p className="text-sm font-medium">Access Token:</p>
|
||||||
|
|
@ -286,7 +283,6 @@ const AuthDebugger = ({
|
||||||
the standard automatic flow.
|
the standard automatic flow.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<OAuthFlowProgress
|
<OAuthFlowProgress
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,9 @@ describe("AuthDebugger", () => {
|
||||||
|
|
||||||
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
|
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
|
||||||
mockRegisterClient.mockResolvedValue(mockOAuthClientInfo);
|
mockRegisterClient.mockResolvedValue(mockOAuthClientInfo);
|
||||||
mockDiscoverOAuthProtectedResourceMetadata.mockResolvedValue(null);
|
mockDiscoverOAuthProtectedResourceMetadata.mockRejectedValue(
|
||||||
|
new Error("No protected resource metadata found")
|
||||||
|
);
|
||||||
mockStartAuthorization.mockImplementation(async (_sseUrl, options) => {
|
mockStartAuthorization.mockImplementation(async (_sseUrl, options) => {
|
||||||
const authUrl = new URL("https://oauth.example.com/authorize");
|
const authUrl = new URL("https://oauth.example.com/authorize");
|
||||||
|
|
||||||
|
|
@ -448,7 +450,7 @@ describe("AuthDebugger", () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
renderAuthDebugger({
|
renderAuthDebugger({
|
||||||
updateAuthState,
|
updateAuthState,
|
||||||
authState: { ...defaultAuthState, loading: false },
|
authState: { ...defaultAuthState },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -471,7 +473,7 @@ describe("AuthDebugger", () => {
|
||||||
).mock.calls.find((call) => call[0] === SESSION_KEYS.AUTH_DEBUGGER_STATE);
|
).mock.calls.find((call) => call[0] === SESSION_KEYS.AUTH_DEBUGGER_STATE);
|
||||||
|
|
||||||
expect(storedStateCall).toBeDefined();
|
expect(storedStateCall).toBeDefined();
|
||||||
const storedState = JSON.parse(storedStateCall![1]);
|
const storedState = JSON.parse(storedStateCall![1] as string);
|
||||||
|
|
||||||
expect(storedState).toMatchObject({
|
expect(storedState).toMatchObject({
|
||||||
oauthStep: "authorization_code",
|
oauthStep: "authorization_code",
|
||||||
|
|
@ -487,4 +489,119 @@ describe("AuthDebugger", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("OAuth Protected Resource Metadata", () => {
|
||||||
|
it("should successfully fetch and display protected resource metadata", async () => {
|
||||||
|
const updateAuthState = jest.fn();
|
||||||
|
const mockResourceMetadata = {
|
||||||
|
resource: "https://example.com/api",
|
||||||
|
authorization_servers: ["https://custom-auth.example.com"],
|
||||||
|
bearer_methods_supported: ["header", "body"],
|
||||||
|
resource_documentation: "https://example.com/api/docs",
|
||||||
|
resource_policy_uri: "https://example.com/api/policy",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock successful metadata discovery
|
||||||
|
mockDiscoverOAuthProtectedResourceMetadata.mockResolvedValue(
|
||||||
|
mockResourceMetadata
|
||||||
|
);
|
||||||
|
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
renderAuthDebugger({
|
||||||
|
updateAuthState,
|
||||||
|
authState: { ...defaultAuthState },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click Guided OAuth Flow to start the process
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(screen.getByText("Guided OAuth Flow"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that the flow started with metadata discovery
|
||||||
|
expect(updateAuthState).toHaveBeenCalledWith({
|
||||||
|
oauthStep: "metadata_discovery",
|
||||||
|
authorizationUrl: null,
|
||||||
|
statusMessage: null,
|
||||||
|
latestError: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click Continue to trigger metadata discovery
|
||||||
|
const continueButton = await screen.findByText("Continue");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(continueButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the metadata to be fetched
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith(
|
||||||
|
"https://example.com"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify the state was updated with the resource metadata
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(updateAuthState).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
resourceMetadata: mockResourceMetadata,
|
||||||
|
authServerUrl: new URL("https://custom-auth.example.com"),
|
||||||
|
oauthStep: "client_registration",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle protected resource metadata fetch failure gracefully", async () => {
|
||||||
|
const updateAuthState = jest.fn();
|
||||||
|
const mockError = new Error("Failed to fetch resource metadata");
|
||||||
|
|
||||||
|
// Mock failed metadata discovery
|
||||||
|
mockDiscoverOAuthProtectedResourceMetadata.mockRejectedValue(mockError);
|
||||||
|
// But OAuth metadata should still work with the original URL
|
||||||
|
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
renderAuthDebugger({
|
||||||
|
updateAuthState,
|
||||||
|
authState: { ...defaultAuthState },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click Guided OAuth Flow
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(screen.getByText("Guided OAuth Flow"));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click Continue to trigger metadata discovery
|
||||||
|
const continueButton = await screen.findByText("Continue");
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(continueButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the metadata fetch to fail
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith(
|
||||||
|
"https://example.com"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify the flow continues despite the error
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(updateAuthState).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
resourceMetadataError: mockError,
|
||||||
|
// Should use the original server URL as fallback
|
||||||
|
authServerUrl: new URL("https://example.com"),
|
||||||
|
oauthStep: "client_registration",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify that regular OAuth metadata discovery was still called
|
||||||
|
expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith(
|
||||||
|
new URL("https://example.com")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ export interface StatusMessage {
|
||||||
export interface AuthDebuggerState {
|
export interface AuthDebuggerState {
|
||||||
isInitiatingAuth: boolean;
|
isInitiatingAuth: boolean;
|
||||||
oauthTokens: OAuthTokens | null;
|
oauthTokens: OAuthTokens | null;
|
||||||
loading: boolean;
|
|
||||||
oauthStep: OAuthStep;
|
oauthStep: OAuthStep;
|
||||||
resourceMetadata: OAuthProtectedResourceMetadata | null;
|
resourceMetadata: OAuthProtectedResourceMetadata | null;
|
||||||
resourceMetadataError:
|
resourceMetadataError:
|
||||||
|
|
@ -47,7 +46,6 @@ export interface AuthDebuggerState {
|
||||||
export const EMPTY_DEBUGGER_STATE: AuthDebuggerState = {
|
export const EMPTY_DEBUGGER_STATE: AuthDebuggerState = {
|
||||||
isInitiatingAuth: false,
|
isInitiatingAuth: false,
|
||||||
oauthTokens: null,
|
oauthTokens: null,
|
||||||
loading: true,
|
|
||||||
oauthStep: "metadata_discovery",
|
oauthStep: "metadata_discovery",
|
||||||
oauthMetadata: null,
|
oauthMetadata: null,
|
||||||
resourceMetadata: null,
|
resourceMetadata: null,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue