From c637b5fd29c9d852e109ca225a9ce1f07dd1705c Mon Sep 17 00:00:00 2001 From: h-tsuboi918 Date: Wed, 24 Jun 2026 01:51:08 +0900 Subject: [PATCH] fix(mcp): Preserve existing auth in mTLS transport HTTP header names are case-insensitive, but the mTLS auth bridge only checked for an exact Authorization key before adding ADC credentials. httpx can pass the existing header as lowercase authorization, causing the user token to be missed. Fixes #6200 --- .../adk/tools/mcp_tool/mcp_session_manager.py | 2 +- .../mcp_tool/test_mcp_session_manager.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/google/adk/tools/mcp_tool/mcp_session_manager.py b/src/google/adk/tools/mcp_tool/mcp_session_manager.py index 1d9e5c80a0..90edbf1f34 100644 --- a/src/google/adk/tools/mcp_tool/mcp_session_manager.py +++ b/src/google/adk/tools/mcp_tool/mcp_session_manager.py @@ -261,7 +261,7 @@ async def before_request( ) return - if 'Authorization' in headers: + if any(key.lower() == 'authorization' for key in headers): logger.debug('Authorization header already present, not overwriting') return diff --git a/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py b/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py index 52d9ebf5ca..5cfc4a6d57 100644 --- a/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py +++ b/tests/unittests/tools/mcp_tool/test_mcp_session_manager.py @@ -1298,6 +1298,25 @@ def mock_refresh(req): assert headers["Authorization"] == "Bearer refreshed_token" + @pytest.mark.skipif(not AIO_SUPPORTED, reason="google.auth.aio not supported") + @pytest.mark.asyncio + async def test_before_request_preserves_lowercase_authorization_header(self): + """An existing lowercase authorization header prevents token injection.""" + from google.adk.tools.mcp_tool.mcp_session_manager import _RefreshableAsyncCredentials + + mock_creds = Mock() + mock_creds.expired = True + mock_creds.token = "service_account_token" + mock_creds.refresh = Mock() + + credentials = _RefreshableAsyncCredentials(mock_creds) + headers = {"authorization": "Bearer user_token"} + + await credentials.before_request(None, "GET", "http://example.com", headers) + + assert headers == {"authorization": "Bearer user_token"} + mock_creds.refresh.assert_not_called() + class TestGoogleAuthAsyncByteStream: