-
Notifications
You must be signed in to change notification settings - Fork 753
[BUG] A2AAgent get_agent_card fails with auth #2006
Description
Strands Version:
Python Version:
Operating System:
Installation Method: pip
Steps to Reproduce
import httpx
from a2a.client import ClientConfig, ClientFactory
from strands import A2AAgent
auth_client = httpx.AsyncClient(headers={"Authorization": "Bearer <token>"})
config = ClientConfig(httpx_client=auth_client)
factory = ClientFactory(config)
agent = A2AAgent(
endpoint="https://<agentcore-endpoint>",
a2a_client_factory=factory,
)
# Triggers get_agent_card() internally — factory auth is ignored
result = agent("Hello")Expected Behavior
get_agent_card() should use the authentication configured via a2a_client_factory when fetching the agent card, so that protected endpoints (AgentCore with IAM SigV4 or OAuth 2.0) are reachable.
Actual Behavior
get_agent_card() always creates a bare httpx.AsyncClient, ignoring any auth:
# Current implementation — ignores a2a_client_factory
async with httpx.AsyncClient(timeout=self.timeout) as client:
resolver = A2ACardResolver(httpx_client=client, base_url=self.endpoint)
self._agent_card = await resolver.get_agent_card()This causes a 403 Forbidden on any endpoint that requires authentication. _get_a2a_client() correctly uses the factory for message sending — only card discovery is broken.
Options Considered
Option A: Add client_config param, deprecate a2a_client_factory
Replace factory with a ClientConfig parameter used for both card resolution and message sending.
Pros:
- Fixes the bug cleanly
- No breaking changes (factory still works with deprecation warning)
ClientConfig.httpx_clientis a public API
Cons:
- Users relying on factory-only features (interceptors, consumers, custom transports) cannot migrate yet
- Deprecation warning would be misleading unless it explicitly calls out the feature gap
- Still needs
getattr(factory, "_config")private attribute access as a fallback for existing factory users
Option B: Fix get_agent_card() to use factory's config directly
Extract the httpx client from the factory and pass it to A2ACardResolver, keeping the factory as-is.
Pros:
- Minimal change, fixes the bug without API surface changes
- Preserves all factory features
Cons:
- Requires
getattr(factory, "_config", None)— accessing a private attribute - If
a2a-pythonrenames_config, silently falls back to unauthenticated (403 returns) - No clean path forward, tech debt remains
Option C: Contribute upstream to a2aproject/a2a-python
Add a public ClientFactory.config property (and optionally a resolve_card() method) to the a2a-python SDK, then use it in Strands.
Pros:
- Fixes the root cause — no private attribute hacks
- Benefits the whole a2a ecosystem, not just Strands
- Aligns with [Feat]: Improve client auth handling a2aproject/a2a-python#445 which maintainers already want to address
- Once merged, Strands can use
factory.configcleanly
Cons:
- Timeline dependency: a2a-python releases roughly every 1-2 weeks, but review could take longer
- They are currently in 1.0 RC prep on a
1.0-devbranch — unclear if amainPR gets attention quickly - Doesn't fix Strands users today
Option D: A2AAgent.connect() async classmethod
Add a factory classmethod that uses ClientFactory.connect() directly, resolving card and creating client in one step with full auth support.
Pros:
- Uses only public a2a-python APIs
- Exposes full a2a-python features (interceptors, consumers, transports)
- Clean async factory pattern, idiomatic Python
Cons:
- New API surface — needs API review
- Doesn't fix the existing
__init__+a2a_client_factorypath - Can't be the only fix; existing users still need a migration path
Recommendation Needed
Decide between:
- Ship Option A now as a short-term fix, pursue Option C upstream in parallel
- Ship Option B as a minimal patch, pursue Option C upstream
- Skip A/B, go straight to Option D as the new recommended API