Skip to content

[BUG] A2AAgent get_agent_card fails with auth #2006

@mkmeral

Description

@mkmeral

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_client is 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-python renames _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:

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-dev branch — unclear if a main PR 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_factory path
  • Can't be the only fix; existing users still need a migration path

Recommendation Needed

Decide between:

  1. Ship Option A now as a short-term fix, pursue Option C upstream in parallel
  2. Ship Option B as a minimal patch, pursue Option C upstream
  3. Skip A/B, go straight to Option D as the new recommended API

Related Issues

Metadata

Metadata

Assignees

Labels

area-a2abugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions