fix: ensure user identity is propagated across A2A requests/sessions#1775
fix: ensure user identity is propagated across A2A requests/sessions#1775onematchfox wants to merge 4 commits intokagent-dev:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes identity propagation for proxy-based authentication by ensuring the controller forwards the authenticated user ID to downstream A2A runtimes via the X-User-Id header (in addition to forwarding Authorization when present), aligning behavior with UnsecureAuthenticator.UpstreamAuth.
Changes:
- Update
ProxyAuthenticator.UpstreamAuthto setX-User-Idfrom the authenticated session principal. - Extend
TestProxyAuthenticator_UpstreamAuthto assertX-User-Idforwarding.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| go/core/internal/httpserver/auth/proxy_authn.go | Forward X-User-Id (and Authorization when available) for upstream A2A requests under proxy auth. |
| go/core/internal/httpserver/auth/proxy_authn_test.go | Add test assertion ensuring X-User-Id is forwarded in UpstreamAuth. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1735789 to
d3a0fa0
Compare
|
Seeing some unexpected behaviour when running this change in a live environment (that I didn't see in testing) - may need some additional changes.so reverting to draft for now until I understand what's going on. |
d3a0fa0 to
1dae4fe
Compare
Without this, downstream A2A runtimes fall back to deriving the caller identity from the context ID (`A2A_USER_<contextID>`) instead of the real authenticated user, because `UserIDCallInterceptor` reads `X-User-Id` rather than the forwarded `Bearer` token. Mirrors the behaviour of [`UnsecureAuthenticator.UpstreamAuth`](https://github.com/kagent-dev/kagent/blob/b50661f858787f6c4de2a73479f492ba82af6ca4/go/core/internal/httpserver/auth/authn.go#L48) which already sets this header. Addresses kagent-dev#1293 (comment) Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
66ee32e to
6750b68
Compare
|
FYI @supreme-gg-gg, I think I might just end up fixing #1771 as part of this |
1fa455f to
6cea9ed
Compare
Previously, agent calls authenticated with a k8s SA Bearer token were attributed to the SA identity (e.g. system:serviceaccount:ns:name) instead of the real caller. This caused sessions to be scoped to the wrong identity. Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
6cea9ed to
a7cd979
Compare
Go (ADK executor): - Extend TokenRoundTripper to inject X-User-Id from Go context on every outgoing request - Wire the authenticated user ID into the Go context in A2aAgentExecutor after extracting it from the call context Python (ADK): - Add a ContextVar in kagent-core to carry the caller's user ID for the duration of an async request task - Set it once in KAgentRequestContextBuilder.build() so it is available before any downstream HTTP calls are made - Read it in KAgentTokenService._add_headers so every outgoing httpx request automatically carries X-User-Id - Remove the redundant per-call X-User-ID headers from KAgentSessionService now that the event hook handles injection uniformly Should fix kagent-dev#1771 as well. Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Prevents unwanted breakage when rolling this out as the new controller won't reject calls from existing agents. May also be desirable in situations were users call A2A endpoints on agents directly (bypassing oauth2-proxy and the controller). Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
a7cd979 to
3b40735
Compare
| } | ||
| tokenString, ok := strings.CutPrefix(authHeader, "Bearer ") | ||
| if !ok { | ||
| return nil, ErrUnauthenticated |
There was a problem hiding this comment.
This is a change in behaviour as it requires that a Bearer token be provided whereas the original code allowed any caller that knew the X-Agent-Name and X-User-Id to bypass use of a Bearer token. By default any agent created via the Agent CRD will supply a Bearer token - so this would only affect direct consumers of the API that are currently relying on this insecurity.
Ensures that caller identity correctly propagates from controller->agent->controller.
Addresses #1293 (comment) and potentially also #1771