fix MCP auth token refresh and disable legacy SSE

This commit is contained in:
Jordan Diaz
2026-07-18 10:03:12 +00:00
parent 9c3d9fb999
commit 987e050539
12 changed files with 437 additions and 128 deletions

View File

@@ -0,0 +1,141 @@
import assert from "node:assert/strict";
import test from "node:test";
import { rebuildApiClient, runWithTokenRefreshRetry } from "../auth/apiClient.js";
import { mcpSessionCredentials, sessionApiClients, sessionCredentials } from "../auth/credentials.js";
import { refreshSessionCredentials } from "../auth/sessionRefresh.js";
const jwt = (expiresIn = 3600) => {
const payload = Buffer.from(JSON.stringify({
exp: Math.floor(Date.now() / 1000) + expiresIn,
})).toString("base64url");
return `header.${payload}.signature`;
};
const credentials = (token) => ({
token,
tokenHash: "hash",
website: "demo.example",
web_url: "https://demo.forge.example",
api_web_url: "http://web:80",
forge_host: "demo.forge.example",
mode: "local",
project_dir: "/opt/acai/webs/owner/demo",
acai_user: "owner",
mcp_secret: "acai_secret",
role: "developer",
});
test("deduplicates concurrent forced refreshes and updates session credentials", async () => {
const sessionId = "refresh-session";
sessionCredentials.set(sessionId, credentials(jwt()));
let calls = 0;
const freshToken = jwt(7200);
const fetcher = async () => {
calls += 1;
await new Promise((resolve) => setTimeout(resolve, 10));
return {
success: true,
token: freshToken,
tokenHash: "fresh-hash",
domain: "demo.example",
web_url: "https://demo.forge.example",
api_web_url: "http://web:80",
project_dir: "/opt/acai/webs/owner/demo",
};
};
const [first, second] = await Promise.all([
refreshSessionCredentials(sessionId, { force: true, fetcher }),
refreshSessionCredentials(sessionId, { force: true, fetcher }),
]);
assert.equal(calls, 1);
assert.equal(first.token, freshToken);
assert.equal(second.token, freshToken);
assert.equal(sessionCredentials.get(sessionId).tokenHash, "fresh-hash");
assert.equal(mcpSessionCredentials.get(sessionId).credentials.mcp_secret, undefined);
mcpSessionCredentials.delete(sessionId);
sessionCredentials.delete(sessionId);
});
test("cached Axios client reads the latest token for every request", async () => {
const sessionId = "axios-session";
sessionCredentials.set(sessionId, credentials("old-token"));
const client = await rebuildApiClient(sessionId);
const observed = [];
client.defaults.adapter = async (config) => {
observed.push(config.headers["X-Acai-Token"]);
return { data: {}, status: 200, statusText: "OK", headers: {}, config };
};
await client.get("/first");
sessionCredentials.set(sessionId, credentials("new-token"));
await client.get("/second");
assert.deepEqual(observed, ["old-token", "new-token"]);
sessionApiClients.delete(sessionId);
sessionCredentials.delete(sessionId);
});
test("403 token failure forces one refresh and retries the original request once", async () => {
const sessionId = "retry-session";
sessionCredentials.set(sessionId, credentials("expired-token"));
let refreshes = 0;
let attempts = 0;
const observed = [];
const fresh = credentials("fresh-token");
const client = await rebuildApiClient(sessionId, {
refreshCredentials: async (_sessionId, options) => {
refreshes += 1;
assert.equal(options.force, true);
sessionCredentials.set(sessionId, fresh);
return fresh;
},
});
client.defaults.adapter = async (config) => {
attempts += 1;
observed.push(config.headers["X-Acai-Token"]);
if (attempts === 1) {
const error = new Error("Request failed with status code 403");
error.config = config;
error.response = { status: 403, data: { error: "Token no valido" } };
throw error;
}
return { data: { success: true }, status: 200, statusText: "OK", headers: {}, config };
};
const response = await client.get("/retry-once");
assert.equal(response.data.success, true);
assert.equal(refreshes, 1);
assert.equal(attempts, 2);
assert.deepEqual(observed, ["expired-token", "fresh-token"]);
sessionApiClients.delete(sessionId);
sessionCredentials.delete(sessionId);
});
test("tool-level retry covers Axios clients outside the cached API client", async () => {
let attempts = 0;
let refreshes = 0;
const operation = async () => {
attempts += 1;
if (attempts === 1) {
const error = new Error("forbidden");
error.response = { status: 403, data: { error: "JWT expired" } };
throw error;
}
return "ok";
};
const result = await runWithTokenRefreshRetry("tool-session", operation, {
refreshCredentials: async (_sessionId, options) => {
refreshes += 1;
assert.equal(options.force, true);
},
});
assert.equal(result, "ok");
assert.equal(attempts, 2);
assert.equal(refreshes, 1);
});