fix(server): propagate auth ContextVars through A2A dispatch boundary#591
Draft
fix(server): propagate auth ContextVars through A2A dispatch boundary#591
Conversation
A2ABearerAuthMiddleware validated bearer tokens but only wrote the principal to scope["user"]/scope["auth"], never setting the current_principal/current_tenant/current_principal_metadata ContextVars. auth_context_factory and adopter code reading current_principal.get() directly got None on every A2A call even after successful auth, causing AdCPAuthenticationError on policies that require a bound principal. Mirrors the existing BearerTokenAuthMiddleware try/finally pattern: set all three vars on auth success; set to None on OPTIONS/discovery pass-throughs; reset unconditionally in finally. Fixes #590 https://claude.ai/code/session_01ETystgT4HH4ZHaAziszjBF
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.
Closes #590
Summary
A2ABearerAuthMiddlewarevalidated bearer tokens on the A2A transport but only stored the authenticatedPrincipalinscope["user"]andscope["auth"]. It never set the module-level ContextVars (current_principal,current_tenant,current_principal_metadata) thatBearerTokenAuthMiddlewaresets on the MCP path. As a result,current_principal.get()returnedNoneinside every A2A handler call even after successful auth — breaking the documented contract ("On success, populatescurrent_principal,current_tenant, andcurrent_principal_metadatafor the duration of the downstream call") for the A2A leg.Root effect: every adopter whose platform method reads
current_principal.get()directly, or whoserequire_authtenant policy depends onauth_context_factorypopulatingAuthInfo, was locked out of A2A while MCP worked fine.The fix mirrors the existing
BearerTokenAuthMiddlewaretry/finally pattern:Principal, reset unconditionally infinally.None(clearing any stale value from an enclosing task context), reset infinally. Matches the MCP middleware's discovery branch.What was tested
pytest tests/test_serve_auth_both.py— 30 passed (including 2 new regression tests)pytest tests/test_auth_middleware.py tests/test_a2a_server.py tests/test_decisioning_dispatch.py— 123 passedtest_ip_pinned_transport.py::test_real_tls_handshake_still_validates_hostnameexcluded — hitsexample.com, unrelated)ruff check src/adcp/server/auth.py— cleanmypy src/adcp/server/auth.py --ignore-missing-imports— no new errors (pre-existingBaseHTTPMiddlewarestub issue at line 197 unchanged)Pre-PR review:
current_principal_metadatanot asserted in unit test (coverage gap, not a correctness risk — set/reset logic is structurally identical for all three tokens); OPTIONS/discovery reset-in-finally not explicitly tested (would require inner app to raise, and ContextVar resets toNonewhich is also the default)None; clearing toNoneon OPTIONS/discovery confirmed correct and matching the MCP middleware's discovery branch; no new attack surfaceSession: https://claude.ai/code/session_01ETystgT4HH4ZHaAziszjBF
Generated by Claude Code