Skip to content

[Bug]: APIKeySecurityScheme implementation parsing falied in the client #220

Closed

Description

@FailedNamed

What happened?

Hello everyone,

I am trying to do an example of an A2A client-server communication with APIKeySecurityScheme authentication.

This problem was mentioned at #165. That issue was closed, but now the problem occurs again.

Environment

  • Windows 10
  • Python 3.13
  • pydantic==2.11.7
  • a2a-sdk==0.2.8

Agent Card Scheme

api_key_scheme = {
    'type': 'apiKey',
    'name': 'X-API-KEY',
    'in': 'header'
}

agent_card = AgentCard(
    name='Currency Agent',
    description='Helps with exchange rates for currencies',
    url=f'http://{host}:{port}/',
    version='1.0.0',
    defaultInputModes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
    defaultOutputModes=CurrencyAgent.SUPPORTED_CONTENT_TYPES,
    capabilities=capabilities,
    skills=[skill],
    securitySchemes={
        "api_key": APIKeySecurityScheme.model_validate(api_key_scheme)
    },
    security=[
        {
            'api_key': []
        }
    ],
)

The Issue

The APIKeySecurityScheme's in field is using an alias. But when the SDK server does model_dump for the AgentCard, it doesn't open by_alias, which causes the .well-known/agent.json endpoint to always return a JSON with "in_" instead of "in":

Example returned content:

{
  "capabilities": {"pushNotifications": true, "streaming": true},
  "defaultInputModes": ["text", "text/plain"],
  "defaultOutputModes": ["text", "text/plain"],
  "description": "Helps with exchange rates for currencies",
  "name": "Currency Agent",
  "security": [{"api_key": []}],
  "securitySchemes": {
    "api_key": {
      "in_": "header",
      "name": "X-API-KEY",
      "type": "apiKey"
    }
  },
  "skills": [{
    "description": "Helps with exchange values between various currencies",
    "examples": ["What is exchange rate between USD and GBP?"],
    "id": "convert_currency",
    "name": "Currency Exchange Rates Tool",
    "tags": ["currency conversion", "currency exchange"]
  }],
  "url": "http://xxxx:10000/",
  "version": "1.0.0"
}

Relevant Code

class APIKeySecurityScheme(BaseModel):
    """API Key security scheme."""

    description: str | None = None
    in_: In = Field(..., alias='in')
    name: str
    type: Literal['apiKey'] = 'apiKey'

async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
    """Handles GET requests for the agent card endpoint."""
    # The public agent card is a direct serialization of the agent_card
    # provided at initialization.
    return JSONResponse(
        self.agent_card.model_dump(mode='json', exclude_none=True)
    )

Impact

This makes the sdk client A2ACardResolver.get_agent_card parse the card response unsuccessfully:

agent_card = AgentCard.model_validate(agent_card_data)

Relevant Log Output

pydantic_core._pydantic_core.ValidationError: 7 validation errors for AgentCard
securitySchemes.api_key.APIKeySecurityScheme.in
  Field required [type=missing, input_value={'in_': 'header', 'name':...-KEY', 'type': 'apiKey'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing
securitySchemes.api_key.HTTPAuthSecurityScheme.scheme
  Field required [type=missing, input_value={'in_': 'header', 'name':...-KEY', 'type': 'apiKey'}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing
securitySchemes.api_key.HTTPAuthSecurityScheme.type
  Input should be 'http' [type=literal_error, input_value='apiKey', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/literal_error
securitySchemes.api_key.OAuth2SecurityScheme.flows

Activity

  1. alberto-atk commented on Jun 20, 2025

    @alberto-atk

    Hello, I am the user that reported #165. I am still facing the problem as they answered me and closed the issue but it's not working with the suggested solution. Hope we have it solved soon🤞

  2. holtskinner commented on Jun 20, 2025

    @holtskinner
    Member

    I think I made a mistake in my response in #165, when using model_validate(), try passing the parameter by_alias=True this should ensure that it uses the alias.

  3. self-assigned this
    on Jun 20, 2025
  4. FailedNamed commented on Jun 21, 2025

    @FailedNamed
    Author

    I think I made a mistake in my response in #165, when using model_validate(), try passing the parameter by_alias=True this should ensure that it uses the alias.我认为我在 #165 的回复中犯了一个错误,当使用 model_validate() 时,尝试传递参数 by_alias=True ,这应该能确保它使用别名。

    I’m aware of this solution and use it in my local environment, but I don’t want to apply the same workaround in the production environment. When will you update the SDK to address this issue? Currently, your SDK client does not set by_alias=True in JSONRPCApplication._handle_get_agent_card.

  5. FailedNamed commented on Jun 21, 2025

    @FailedNamed
    Author

    Hello, I am the user that reported #165. I am still facing the problem as they answered me and closed the issue but it's not working with the suggested solution. Hope we have it solved soon🤞

    Currently, the only solution is to modify the SDK code directly, specifically in jsonrpc_app.py, to use by_alias=True as shown below:

    async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
        """
        Handles GET requests for the agent card endpoint.
    
        Args:
            request: The incoming Starlette Request object.
    
        Returns:
            A JSONResponse containing the agent card data.
        """
        # The public agent card is directly serialized from the agent_card provided at initialization.
        return JSONResponse(
            self.agent_card.model_dump(mode='json', by_alias=True, exclude_none=True)
        )

    It would be great if they could update the SDK to implement this fix, so we don't have to manually alter the code in the release environment.

  6. added a commit that references this issue on Jun 23, 2025
    5e249bb
  7. holtskinner commented on Jun 23, 2025

    @holtskinner
    Member

    Sorry, I got confused on the specific issue you were having. I made PR #226 to add this field. Can you verify that this version resolves the issue?

    Hello, I am the user that reported #165. I am still facing the problem as they answered me and closed the issue but it's not working with the suggested solution. Hope we have it solved soon🤞

    Currently, the only solution is to modify the SDK code directly, specifically in jsonrpc_app.py, to use by_alias=True as shown below:

    async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
    """
    Handles GET requests for the agent card endpoint.

    Args:
        request: The incoming Starlette Request object.
    
    Returns:
        A JSONResponse containing the agent card data.
    """
    # The public agent card is directly serialized from the agent_card provided at initialization.
    return JSONResponse(
        self.agent_card.model_dump(mode='json', by_alias=True, exclude_none=True)
    )
    

    It would be great if they could update the SDK to implement this fix, so we don't have to manually alter the code in the release environment.

  8. FailedNamed commented on Jun 23, 2025

    @FailedNamed
    Author

    Sorry, I got confused on the specific issue you were having. I made PR #226 to add this field. Can you verify that this version resolves the issue?抱歉,我没能完全理解你遇到的具体问题。我提交了 PR #226 来添加这个字段。你能验证这个版本是否解决了问题吗?

    Hello, I am the user that reported #165. I am still facing the problem as they answered me and closed the issue but it's not working with the suggested solution. Hope we have it solved soon🤞你好,我是那个报告问题的人。他们回复我并关闭了问题,但我仍然遇到同样的问题,建议的解决方案不起作用。希望我们能尽快解决它🤞

    Currently, the only solution is to modify the SDK code directly, specifically in jsonrpc_app.py, to use by_alias=True as shown below:目前,唯一的解决方案是直接修改 SDK 代码,具体是在 jsonrpc_app.py 中使用 by_alias=True,如下所示:
    async def _handle_get_agent_card(self, request: Request) -> JSONResponse:
    """
    Handles GET requests for the agent card endpoint. 处理获取代理卡端点的 GET 请求。

    Args:
        request: The incoming Starlette Request object.
    
    Returns:
        A JSONResponse containing the agent card data.
    """
    # The public agent card is directly serialized from the agent_card provided at initialization.
    return JSONResponse(
        self.agent_card.model_dump(mode='json', by_alias=True, exclude_none=True)
    )
    

    It would be great if they could update the SDK to implement this fix, so we don't have to manually alter the code in the release environment.如果他们能更新 SDK 来实现这个修复,那就太好了,这样我们就不必在发布环境中手动修改代码了。

    Yes, I use this in my local environment, and then the agent card can be successfully parsed by the a2a client.

  9. added 3 commits that reference this issue on Jun 23, 2025
    aa63b98
    f9b4e5a
    52b6169
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions