-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Open
Feature
Copy link
Labels
bot triaged[Bot] This issue is triaged by ADK bot[Bot] This issue is triaged by ADK bottools[Component] This issue is related to tools[Component] This issue is related to tools
Milestone
Description
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]
To Reproduce
Steps to reproduce the behavior:
- Create python environment
uv venv --python 3.12.0
source .venv/bin/activate
uv pip install google-adk==1.8.0
- Use this openapi.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"
}
}
}
}
- use test_tool.py to testing.
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())
- 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_=<SecuritySchemeType.apiKey: 'apiKey'> description=None in_=<APIKeyIn.header: 'header'> name='x-api-key-1'
- The other way you can test it is using this agent.py
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:
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

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
Metadata
Metadata
Assignees
Labels
bot triaged[Bot] This issue is triaged by ADK bot[Bot] This issue is triaged by ADK bottools[Component] This issue is related to tools[Component] This issue is related to tools