Skip to content

fix: changeable allowed_client_redirect_uris on OAuthProxy#3772

Merged
jlowin merged 1 commit intoPrefectHQ:mainfrom
fengarix:fix/oauth-proxy-allowed-redirect-uris
Apr 7, 2026
Merged

fix: changeable allowed_client_redirect_uris on OAuthProxy#3772
jlowin merged 1 commit intoPrefectHQ:mainfrom
fengarix:fix/oauth-proxy-allowed-redirect-uris

Conversation

@fengarix
Copy link
Copy Markdown
Contributor

@fengarix fengarix commented Apr 6, 2026

Description

On OAuthProxy.get_client(), prioritized self._allowed_client_redirect_uris rather than stored allowed_redirect_uri_patterns from stored client. Without this fix, any updates to allowed_client_redirect_uris are prohibited, e.g., fixing typos, or client's url updates.

Closes #3771

Contribution type

  • Bug fix (simple, well-scoped fix for a clearly broken behavior)
  • Documentation improvement
  • Enhancement (maintainers typically implement enhancements — see CONTRIBUTING.md)

Checklist

  • This PR addresses an existing issue (or fixes a self-evident bug)
  • I have read CONTRIBUTING.md
  • I have added tests that cover my changes
  • I have run uv run prek run --all-files and all checks pass
  • I have self-reviewed my changes
  • If I used an LLM, it followed the repo's contributing conventions (not generic output)

@marvin-context-protocol marvin-context-protocol Bot added bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. auth Related to authentication (Bearer, JWT, OAuth, WorkOS) for client or server. labels Apr 6, 2026
@marvin-context-protocol
Copy link
Copy Markdown
Contributor

Test Failure Analysis

Summary: A pre-existing flaky test in tests/server/middleware/test_rate_limiting.py failed on Python 3.13. This failure is unrelated to the changes in this PR, which only modifies OAuth proxy logic.

Root Cause: TestRateLimitingMiddlewareIntegration.test_rate_limiting_with_different_operations (line 381) has a fragile assumption about internal MCP request counts. The test uses burst_capacity=5 and expects the 3rd call_tool (batch_process) to be rate-limited. However, the server receives exactly 5 requests before/during that call — 2 list_tools + 3 call_tool operations — which perfectly fits the burst capacity, so no rate limit is triggered.

The test is also inherently timing-dependent: with max_requests_per_second=9.0, even small gaps between requests (e.g., the 10ms sleep in heavy_computation) can cause token refills, making the test pass or fail non-deterministically. The PR's 3 prior CI runs confirm this — it passed twice and failed once.

Suggested Solution: This is a pre-existing flaky test that should be fixed separately from this PR. The fix would mirror the pattern already used in test_rate_limiting_blocks_rapid_requests — use a near-zero refill rate (max_requests_per_second=0.001) with a large enough burst for initialization overhead, then loop until the limit is hit rather than relying on an exact request count:

async def test_rate_limiting_with_different_operations(self, rate_limit_server):
    """Test that rate limiting applies to all types of operations."""
    rate_limit_server.add_middleware(
        RateLimitingMiddleware(max_requests_per_second=0.001, burst_capacity=20)
    )

    async with Client(rate_limit_server) as client:
        operations = cycle([
            ("quick_action", {"message": "test"}),
            ("heavy_computation", {}),
            ("batch_process", {"items": ["a", "b", "c"]}),
        ])
        hit_limit = False
        for _, (tool_name, args) in zip(range(30), operations):
            try:
                await client.call_tool(tool_name, args)
            except ToolError as exc:
                assert "Rate limit exceeded" in str(exc)
                hit_limit = True
                break
        assert hit_limit, "Rate limit was never triggered across different operations"
Detailed Analysis

Failing test: tests/server/middleware/test_rate_limiting.py::TestRateLimitingMiddlewareIntegration::test_rate_limiting_with_different_operations

Log excerpt:

E           Failed: DID NOT RAISE <class 'fastmcp.exceptions.ToolError'>
tests/server/middleware/test_rate_limiting.py:393: Failed

Server-side request trace (from captured debug logs):

  1. list_tools — token 1
  2. call_tool quick_action — token 2
  3. list_tools — token 3
  4. call_tool heavy_computation — token 4
  5. call_tool batch_process — token 5 ✅ (should fail, doesn't)

With burst_capacity=5, all 5 requests fit within the burst. The test assumed there would be 6+ requests (e.g., an initialize message also consuming a token), but initialize does not appear to go through on_request in this middleware.

Why only Python 3.13? On the 3 prior CI runs for this PR, 2 succeeded and 1 failed. The failures are intermittent, consistent with timing sensitivity. Python 3.13's asyncio may schedule coroutines with slightly different timing, affecting how many tokens refill between requests.

PR diff: The PR only changes src/fastmcp/server/auth/oauth_proxy/proxy.py and tests/server/auth/oauth_proxy/test_client_registration.py — completely unrelated to rate limiting.

Related Files
  • tests/server/middleware/test_rate_limiting.py:381 — failing test with fragile burst_capacity assumption
  • src/fastmcp/server/middleware/rate_limiting.py:152RateLimitingMiddleware.on_request (the middleware itself is correct)
  • tests/server/middleware/test_rate_limiting.py:307test_rate_limiting_blocks_rapid_requests — the robust pattern this test should follow

Copy link
Copy Markdown
Member

@jlowin jlowin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@jlowin jlowin merged commit 5587cb7 into PrefectHQ:main Apr 7, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth Related to authentication (Bearer, JWT, OAuth, WorkOS) for client or server. bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot change allowed_client_redirect_uris for stored client of OAuthProxy

2 participants