Skip to content

Commit c99e72c

Browse files
fix: forward the effective user to the Agent API in Vite
Vite has no nginx auth_request, so the Agent tab 401'd on profile/switch. Send X-Remote-User from /api/agent/session's username (including impersonation) and replay it on SSE via the proxy. Co-authored-by: Venkat SF <venkatesh.sakamuri@stayflexi.com>
1 parent 2b204f8 commit c99e72c

2 files changed

Lines changed: 36 additions & 1 deletion

File tree

src/lib/api/agentClient.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,26 @@ const CSRF_HEADER = "X-Hermes-CSRF-Token";
2020
/** Cached CSRF token for the agent API (required once trusted-auth is on). */
2121
let agentCsrfToken = null;
2222

23+
/**
24+
* Effective DeepSQL username from the last `/api/agent/session` bootstrap.
25+
* Vite has no nginx `auth_request` to stamp `X-Remote-User`, so the browser
26+
* must send it. Never hardcode a user — impersonation ("View as") changes this.
27+
*/
28+
let agentRemoteUser = null;
29+
30+
function withAgentAuthHeaders(headers = {}) {
31+
if (agentRemoteUser) {
32+
headers["X-Remote-User"] = agentRemoteUser;
33+
}
34+
return headers;
35+
}
36+
2337
async function ensureAgentCsrf() {
2438
if (agentCsrfToken) return agentCsrfToken;
25-
const res = await fetch(`${AGENT_BASE}/api/auth/status`, { credentials: "include" });
39+
const res = await fetch(`${AGENT_BASE}/api/auth/status`, {
40+
credentials: "include",
41+
headers: withAgentAuthHeaders(),
42+
});
2643
if (!res.ok) return null;
2744
const data = await res.json().catch(() => ({}));
2845
agentCsrfToken = data?.csrf_token || null;
@@ -35,6 +52,7 @@ async function postJson(url, body, _retried = false) {
3552
// enables the agent auth gate, unsafe POSTs need the session CSRF token or
3653
// the agent answers 403 "Session expired - reload the page".
3754
if (url.startsWith(AGENT_BASE) || url.includes("/agent-api/")) {
55+
withAgentAuthHeaders(headers);
3856
const csrf = await ensureAgentCsrf();
3957
if (csrf) headers[CSRF_HEADER] = csrf;
4058
}
@@ -99,6 +117,7 @@ export const agentChatAPI = {
99117
/** Resolve/provision the current user's agent profile (via Spring → cookie auth). */
100118
async bootstrap(connectionId) {
101119
const data = await postJson("/api/agent/session", { connectionId });
120+
if (data?.username) agentRemoteUser = data.username;
102121
// Must happen before any session/new / resume path that hits /agent-api.
103122
try {
104123
await switchAgentProfile(data?.profile);

vite.config.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,22 @@ export default defineConfig({
6262
rewrite: (p) => p.replace(/^\/agent-api/, ''),
6363
timeout: 300000,
6464
proxyTimeout: 300000,
65+
// Production nginx stamps X-Remote-User via auth_request. Vite has no
66+
// equivalent, so the browser sends the effective username (including
67+
// impersonation). EventSource cannot set headers — remember the last
68+
// value and attach it to SSE / other proxied calls.
69+
configure: (proxy) => {
70+
let lastRemoteUser
71+
proxy.on('proxyReq', (proxyReq, req) => {
72+
const incoming = req.headers['x-remote-user']
73+
if (typeof incoming === 'string' && incoming.trim()) {
74+
lastRemoteUser = incoming.trim()
75+
}
76+
if (lastRemoteUser) {
77+
proxyReq.setHeader('X-Remote-User', lastRemoteUser)
78+
}
79+
})
80+
},
6581
},
6682
},
6783
},

0 commit comments

Comments
 (0)