Repository navigation
Conversation
🔍 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:
|
|
Hi @f4x0rz , Thank you for your contribution! It appears you haven't yet signed the Contributor License Agreement (CLA). Please visit https://cla.developers.google.com/ to complete the signing process. Once the CLA is signed, we'll be able to proceed with the review of your PR. Thank you! |
|
@rohityan The CLA is signed under the email associated with both commits in this PR (matching the git author metadata). The cla/google check appears to be using a stale result from before the signature went through. @googlebot I signed it |
|
Hi @f4x0rz, Thank you again for this contribution! We checked the CLA status for your PR and noticed an interesting detail: you have already signed the Google CLA (thank you!), but the check is currently failing because the latest commit message includes: Google's automated CLA checker treats that address as a co-author and requires a signed CLA for it. To resolve this, you just need to remove the git commit --amend # remove the Co-Authored-By trailer
git push --forceBecause this pull request has been open for over 4 months without an active CLA pass, we kindly ask if you could help update the commit within the next 2 weeks. If there is no update or if the CLA remains unresolved after 2 weeks, we will respectfully close this PR to keep the backlog tidy (you are always welcome to reopen or resubmit once resolved). We really appreciate your time and patience with our process! |
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).
Combines a wrapped `await middleware(...)` call onto a single line per the project's pyink configuration. No behavior change.
285caa2 to
dc9a274
Compare
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)