fix(api_server): add optional ADK_API_TOKEN Bearer auth middleware#5981
Open
f4x0rz wants to merge 1 commit into
Open
fix(api_server): add optional ADK_API_TOKEN Bearer auth middleware#5981f4x0rz wants to merge 1 commit into
f4x0rz wants to merge 1 commit into
Conversation
ApiServer registers /run, /run_sse, and the session CRUD routes without per-route authentication. When the server is bound to a network-reachable address with no upstream auth layer, those routes reach in-process Python code execution (UnsafeLocalCodeExecutor.execute_code) and per-user session state without any caller identity check. This change adds an ASGI middleware that is a no-op when ADK_API_TOKEN is unset (preserving the current behavior for deployments that gate access upstream) and that requires a matching Authorization: Bearer <token> header on every non-public request when ADK_API_TOKEN is set. /health and /version remain open so liveness probes do not need credentials. The middleware mirrors the shape of the existing _OriginCheckMiddleware and _DefaultAppRewriteMiddleware in the same file. The fix is the smallest opt-in path that turns the existing unauth surface into authenticated endpoints without changing any user-facing API or breaking deployments that already wire their own auth. Refs: Google bug-tracker issue 509219988 (reporter request to provide a patch alongside the report).
Collaborator
🔍 ADK Pull Request Analysis: PR #5981Title: fix(api_server): add optional ADK_API_TOKEN Bearer auth middleware 🛡️ Critical Compliance Gate: Google CLA VerificationBefore analyzing this PR's diff and local workspace file structure, we verified the contributor's Google Contributor License Agreement (CLA) status:
Executive Summary
Detailed Findings & Analysis1. Objectives & Impact ("What does it do?")
2. Justification & Value ("Is it a valid and useful change?")
3. Principle & Style Alignment Checklist ("Does it follow rules?")
🛠️ Requested Updates / Design FixesTo achieve full alignment, we recommend providing the following feedback to the contributor on the pull request:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional
ADK_API_TOKENBearer auth middleware to the ApiServer.Why
The ApiServer registers
/run,/run_sse, and the session CRUD routes (/apps/{app}/users/{user}/sessions/...) without per-route authentication. When an operator binds the server to a network-reachable address with no upstream auth layer (reverse proxy, sidecar, IAP, network policy), those routes reach in-process Python code execution viaUnsafeLocalCodeExecutor.execute_codeand per-user session state with no caller identity check.This is the smallest opt-in mitigation that does not break any existing deployment.
Behavior
ADK_API_TOKENunset or empty: no-op, every request passes through unchanged. This preserves current behavior for deployments that already gate access upstream.ADK_API_TOKENset: every request other thanGET /healthandGET /versionmust carry anAuthorization: Bearer <token>header whose token equalsADK_API_TOKEN, otherwise the request is rejected with HTTP 401 and aWWW-Authenticate: Bearer realm="adk"header. Liveness probes do not need credentials.The middleware mirrors the shape of the existing
_OriginCheckMiddlewareand_DefaultAppRewriteMiddlewarein the same file.Testing Plan
Setup, on Windows 11, Python 3.13.13:
Unit tests
Output:
Manual integration test via uvicorn + curl
A minimal Starlette app wraps the middleware around a stub
/run,/health, and/version(same shape the real ApiServer uses atapi_server.py:1048):Start uvicorn for each scenario, then fire curl.
Scenario 1:
ADK_API_TOKENunset (default). Every route open.Scenario 2:
ADK_API_TOKEN=secret-12345, no token from client. HTTP 401 withWWW-Authenticate.Scenario 3:
ADK_API_TOKEN=secret-12345, correct token from client. HTTP 200, downstream invoked.Why this opens against
google/adk-pythonIssue 509219988 tracks the underlying auth gap report; per the maintainer's 2026-06-04 note ("the more comprehensive solution would be to allow the server to be deployed with an authentication dependency... If you would like to provide a fix yourself it helps speed up our validation process"), this PR is the proposed fix.
This PR supersedes #5980, which was opened from a fork on the wrong GitHub account.
Files changed
src/google/adk/cli/api_server.py(+ middleware class, +app.add_middlewarewiring)tests/unittests/cli/test_bearer_auth_middleware.py(new, 9 tests)