Skip to content

feat(ui): UI does not have ability to forward headers that are not authorization#1776

Open
jholt96 wants to merge 2 commits intokagent-dev:mainfrom
jholt96:ui-headers
Open

feat(ui): UI does not have ability to forward headers that are not authorization#1776
jholt96 wants to merge 2 commits intokagent-dev:mainfrom
jholt96:ui-headers

Conversation

@jholt96
Copy link
Copy Markdown
Contributor

@jholt96 jholt96 commented Apr 29, 2026

Add an allowlist env for forwarding additional headers to the backend from oauth2-proxy. This allowed for setting additional headers from oauth2-proxy or other services such as X-Auth-Request-User, X-Auth-Request-Email, X-Auth-Request-Groups, X-Forwarded-User, X-Forwarded-Groups.

We are working on an use case where we set a custom header -> goes through oauth2-proxy -> UI -> controller -> agent -> MCP server. The MCP server uses that header to validate the user before running any tool call as an additional layer of rbac

Copilot AI review requested due to automatic review settings April 29, 2026 12:50
@github-actions github-actions Bot added the enhancement New feature or request label Apr 29, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a configurable allowlist for forwarding additional request headers from the UI (behind oauth2-proxy) to the backend, enabling propagation of identity/metadata headers beyond Authorization across the UI → controller/agent → MCP chain.

Changes:

  • Add KAGENT_ADDITIONAL_FORWARDED_HEADERS env parsing + blocklist enforcement to forward extra headers alongside authorization.
  • Update UI backend proxying calls to spread forwarded headers first so explicit Content-Type/Accept values win.
  • Expand A2A/A2A-sandbox CORS Access-Control-Allow-Headers to include the configured forwarded header names; add Helm values + deployment env wiring.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
ui/src/lib/auth.ts Implements additional-forwarded-header allowlist with a blocked header set and exposes allowed header names.
ui/src/app/actions/utils.ts Adjusts header merge order so explicit content negotiation headers override forwarded ones.
ui/src/app/a2a/[namespace]/[agentName]/route.ts Forwards additional headers to backend and derives CORS allow-headers from the allowed-forward list.
ui/src/app/a2a-sandboxes/[namespace]/[agentName]/route.ts Same as above for sandbox A2A route.
helm/kagent/values.yaml Adds ui.additionalForwardedHeaders values knob and docs.
helm/kagent/templates/ui-deployment.yaml Wires ui.additionalForwardedHeaders into KAGENT_ADDITIONAL_FORWARDED_HEADERS env var.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ui/src/lib/auth.ts
Comment on lines +7 to +19
const BLOCKED_FORWARD_HEADERS = new Set([
"host",
"connection",
"keep-alive",
"transfer-encoding",
"upgrade",
"te",
"trailer",
"proxy-authenticate",
"proxy-authorization",
"content-length",
"content-encoding",
]);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

personally i think this is not needed as at least for the oauth2-proxy cookie that should be encrypted. lmk what you all think and I can add it

Comment thread ui/src/lib/auth.ts Outdated
Comment on lines +27 to +63
function parseAllowedHeaders(): Set<string> {
const allowed = new Set<string>(DEFAULT_FORWARD_HEADERS);
const raw = process.env.KAGENT_ADDITIONAL_FORWARDED_HEADERS;
if (!raw) {
return allowed;
}

const blockedFromEnv: string[] = [];
for (const part of raw.split(",")) {
const name = part.trim().toLowerCase();
if (!name) continue;
if (BLOCKED_FORWARD_HEADERS.has(name)) {
blockedFromEnv.push(name);
continue;
}
allowed.add(name);
}

if (blockedFromEnv.length > 0 && !warnedBlocked) {
warnedBlocked = true;
console.warn(
`KAGENT_ADDITIONAL_FORWARDED_HEADERS contains hop-by-hop or routing headers that will not be forwarded: ${blockedFromEnv.join(", ")}`
);
}

return allowed;
}

const ALLOWED_FORWARD_HEADERS = parseAllowedHeaders();

/**
* Extract authentication headers from a headers-like object.
* Common implementation used by both server actions and route handlers.
* Returns the list of header names (lowercased) the proxy will forward.
* Always includes "authorization"; extends with KAGENT_ADDITIONAL_FORWARDED_HEADERS.
*/
function extractAuthHeaders(getHeader: (name: string) => string | null): Record<string, string> {
const authHeaders: Record<string, string> = {};
export function getAllowedForwardHeaderNames(): string[] {
return Array.from(ALLOWED_FORWARD_HEADERS);
}
Comment on lines +5 to +11
function buildCorsAllowHeaders(): string {
const names = new Set<string>(['content-type', 'accept']);
for (const name of getAllowedForwardHeaderNames()) {
names.add(name);
}
return Array.from(names).join(', ');
}
Comment thread ui/src/app/a2a/[namespace]/[agentName]/route.ts
Comment on lines +5 to +11
function buildCorsAllowHeaders(): string {
const names = new Set<string>(['content-type', 'accept']);
for (const name of getAllowedForwardHeaderNames()) {
names.add(name);
}
return Array.from(names).join(', ');
}
Comment thread ui/src/app/a2a-sandboxes/[namespace]/[agentName]/route.ts
Comment thread helm/kagent/values.yaml
env: {} # Additional configuration key-value pairs for the ui ConfigMap
# -- Additional request headers (beyond Authorization) the UI proxy will forward
# to the backend. Names are case-insensitive. Hop-by-hop headers (Connection,
# Transfer-Encoding, etc.) are silently dropped.
Copy link
Copy Markdown
Contributor

@EItanya EItanya left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this PR makes a ton of sense to me, I do think the copilot comments are worth addressing first.

import { getAuthHeadersFromRequest } from '@/lib/auth';
import { getAuthHeadersFromRequest, getAllowedForwardHeaderNames } from '@/lib/auth';

function buildCorsAllowHeaders(): string {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks the same as buildCorsAllowHeaders

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean by this but can you re review? I am fairly rusty with Typescript so want to make sure this looks good to everyone

…thorization

Add an allowlist env for forwarding additional headers to the backend from oauth2-proxy

Signed-off-by: Josh Holt <jholt96@live.com>
@jholt96
Copy link
Copy Markdown
Contributor Author

jholt96 commented May 1, 2026

implemented copilot suggested changes and added tests for this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants