From 892e1731f7f651eb847eac38ca1bb9aa714acfe1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 25 Feb 2026 21:30:47 +0000 Subject: [PATCH] Allow http_client with static public_key in JWTVerifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with Claude Code https://claude.ai/code/session_012QKWmKd21vypDmxWbwuE4e --- src/fastmcp/server/auth/providers/jwt.py | 3 ++- .../server/auth/providers/test_http_client.py | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/fastmcp/server/auth/providers/jwt.py b/src/fastmcp/server/auth/providers/jwt.py index 783499faa..5640fa390 100644 --- a/src/fastmcp/server/auth/providers/jwt.py +++ b/src/fastmcp/server/auth/providers/jwt.py @@ -201,7 +201,8 @@ class JWTVerifier(TokenVerifier): if public_key and jwks_uri: raise ValueError("Provide either public_key or jwks_uri, not both") - if ssrf_safe and http_client is not None: + # Only enforce ssrf_safe/http_client exclusivity when JWKS fetching is used + if jwks_uri and ssrf_safe and http_client is not None: raise ValueError( "http_client cannot be used with ssrf_safe=True; " "SSRF-safe mode requires its own hardened transport" diff --git a/tests/server/auth/providers/test_http_client.py b/tests/server/auth/providers/test_http_client.py index 8beb443e2..34c118f38 100644 --- a/tests/server/auth/providers/test_http_client.py +++ b/tests/server/auth/providers/test_http_client.py @@ -180,11 +180,11 @@ class TestJWTVerifierHttpClient: assert result is not None assert not shared_client.is_closed - def test_ssrf_safe_rejects_http_client( + def test_ssrf_safe_rejects_http_client_with_jwks( self, shared_client: httpx.AsyncClient, ): - """ssrf_safe=True and http_client cannot be used together.""" + """ssrf_safe=True and http_client cannot be used together with JWKS.""" with pytest.raises(ValueError, match="cannot be used with ssrf_safe=True"): JWTVerifier( jwks_uri="https://auth.example.com/.well-known/jwks.json", @@ -192,6 +192,21 @@ class TestJWTVerifierHttpClient: http_client=shared_client, ) + def test_ssrf_safe_allows_http_client_with_static_key( + self, + rsa_key_pair: RSAKeyPair, + shared_client: httpx.AsyncClient, + ): + """ssrf_safe with http_client is allowed when using static public_key (no HTTP).""" + # This should NOT raise — static key means no JWKS fetching + verifier = JWTVerifier( + public_key=rsa_key_pair.public_key, + ssrf_safe=True, + http_client=shared_client, + ) + assert verifier._http_client is shared_client + assert verifier.ssrf_safe is True + class TestGitHubHttpClient: """Test http_client parameter on GitHubTokenVerifier."""