Returning undefined from discoverOAuthMetadata for CORS errors (#717)

* Returning undefined from `discoverOAuthMetadata` for CORS errors

This behaviour was already happening for the root URL, but the new `fetchWithCorsRetry` logic differed.

The issue was if the server returns a 404 for `/.well-known/oauth-authorization-server/xyz` that didn't have the `access-control-allow-origin`, a TypeError was being thrown. There was logic there already to handle a TypeError for a _preflight_ request (cause by custom headers), but not the fallback. I refactored so all combinations return `undefined`.

* Add test for CORS error handling that should return undefined

This test covers the scenario where both the initial request with headers
and the retry without headers fail with CORS TypeErrors. The desired
behavior is to return undefined instead of throwing.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix test comment

---------

Co-authored-by: Glen Maddern <glen@glenmaddern.com>
Co-authored-by: Paul Carleton <paulc@anthropic.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Paul Carleton <paulcarletonjr@gmail.com>
This commit is contained in:
Glen Maddern 2025-07-02 01:24:27 +10:00 • committed by GitHub
commit 6f5e53b44b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -403,6 +403,19 @@ describe("OAuth Authorization", () => {
expect(mockFetch).toHaveBeenCalledTimes(2);
});
it("returns undefined when both CORS requests fail in fetchWithCorsRetry", async () => {
// fetchWithCorsRetry tries with headers (fails with CORS), then retries without headers (also fails with CORS)
// simulating a 404 w/o headers set. We want this to return undefined, not throw TypeError
mockFetch.mockImplementation(() => {
// Both the initial request with headers and retry without headers fail with CORS TypeError
return Promise.reject(new TypeError("Failed to fetch"));
});
// This should return undefined (the desired behavior after the fix)
const metadata = await discoverOAuthMetadata("https://auth.example.com/path");
expect(metadata).toBeUndefined();
});
it("returns undefined when discovery endpoint returns 404", async () => {
mockFetch.mockResolvedValueOnce({
ok: false,