google / google/adk-python

OpenAPIToolset does not support tools (endpoints) that have multiple security definitions.

Abierto
#2,228 6 comentarios 0 reacciones 1 asignado Reclamado por @seanzhou1023 Ver en GitHub
needs review tools
Lenguaje dominante
Python
Estrellas
21.5k
Forks
4k
Merge medio
1 d 14 h
PR fusionados (30 d)
37

Descripción

**Describe the bug**
OpenAPIToolset and APIHubToolset only allow each tool to have a single security schema.
For example:
If your endpoint(tool) required multiple security, then OpenAPIToolset and APIHubToolset will only choose the first one become its auth_scheme [1]

[1] https://github.com/google/adk-python/blob/main/src/google/adk/tools/openapi_tool/openapi_spec_parser/openapi_spec_parser.py#L129-L136

**To Reproduce**
Steps to reproduce the behavior:
1. Create python environment
```cmd
uv venv --python 3.12.0
source .venv/bin/activate
uv pip install google-adk==1.8.0
```
2. Use this openapi.json
```json
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"servers": [
{
"url": "http://localhost:8080"
}
],
"paths": {
"/helloworld": {
"get": {
"summary": "Helloworld",
"operationId": "helloworld_helloworld_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {

}
}
}
}
},
"security": [
{
"api1": []
},
{
"api2": []
}
]
}
}
},
"components": {
"securitySchemes": {
"api1": {
"type": "apiKey",
"in": "header",
"name": "x-api-key-1"
},
"api2": {
"type": "apiKey",
"in": "header",
"name": "x-api-key-2"
}
}
}
}
```
3. use test_tool.py to testing.
```python
import os
import json
from google.auth import default
from google.auth.transport.requests import Request
from google.cloud import secretmanager
from google.adk.tools.apihub_tool.apihub_toolset import APIHubToolset
from google.adk.agents.llm_agent import LlmAgent
from google.adk.auth.auth_credential import AuthCredential, AuthCredentialTypes, HttpAuth, HttpCredentials
from google.adk.tools.openapi_tool.auth.auth_helpers import token_to_scheme_credential
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset
import asyncio

OPENAPI_SPEC_FILENAME="hello_world_openapi.json"
TOKEN="secret-key-1"

with open(os.path.join(os.path.dirname(__file__), OPENAPI_SPEC_FILENAME), 'r') as f:
spec_content = f.read()

auth_scheme, auth_credential = token_to_scheme_credential(
"apikey", "header", "x-api-key-1", TOKEN
)

smorch_toolset = OpenAPIToolset(
spec_str=spec_content,
spec_str_type='json',
auth_scheme=auth_scheme,
auth_credential=auth_credential
)

async def main():
tools = await smorch_toolset.get_tools()
for tool in tools:
print(tool.auth_scheme)

asyncio.run(main())

```
4. tool only have one auth_scheme (x-api-key-1), x-api-key-2 is missing....
```
(adk_with_different_auth) user@abehsu-us-vscode:~/abehsu/fastapi_with_multiple_security$ python /home/user/abehsu/adk_with_different_auth/api_key/openapi/test_tool.py
type_= description=None in_= name='x-api-key-1'
```

5. The other way you can test it is using this agent.py
```python
import os
from google.adk.agents.llm_agent import LlmAgent
from google.adk.tools.openapi_tool.auth.auth_helpers import token_to_scheme_credential
from google.adk.tools.openapi_tool.openapi_spec_parser.openapi_toolset import OpenAPIToolset

OPENAPI_SPEC_FILENAME="hello_world_openapi.json"
TOKEN="secret-key-1"

with open(os.path.join(os.path.dirname(__file__), OPENAPI_SPEC_FILENAME), 'r') as f:
spec_content = f.read()

auth_scheme, auth_credential = token_to_scheme_credential(
"apikey", "header", "x-api-key-1", TOKEN
)

hello_world_toolset = OpenAPIToolset(
spec_str=spec_content,
spec_str_type='json',
auth_scheme=auth_scheme,
auth_credential=auth_credential
)

# --- Agent Configuration ---
# Configure and create the main LLM Agent.
root_agent = LlmAgent(
model='gemini-2.0-flash',
name='hello_world_agent',
instruction='when user say hi you will use hello world tool to response them',
tools=[hello_world_toolset],
)

```

Backend server example code:
```python
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import APIKeyHeader

api_key_header_1 = APIKeyHeader(name="x-api-key-1", auto_error=False, scheme_name="api1")
api_key_header_2 = APIKeyHeader(name="x-api-key-2", auto_error=False, scheme_name="api2")

SECRET_KEY_1 = "secret-key-1"
SECRET_KEY_2 = "secret-key-2"

async def get_api_keys_1(
key1: str = Depends(api_key_header_1),
key2: str = Depends(api_key_header_2),
):
if not key1 or key1 != SECRET_KEY_1:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or missing API Key 1",
)
if not key2 or key2 != SECRET_KEY_2:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or missing API Key 2",
)
return key1, key2

app = FastAPI()

@app.get("/helloworld", dependencies=[Depends(get_api_keys_1)])
async def helloworld():
return {"message": "Hello World"}

```

**Screenshots**

Image

**Desktop (please complete the following information):**
- OS: Linux
- Python version(python -V): Python 3.12.10
- ADK version(pip show google-adk): 1.18.0

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.