feat(http): allow config.apiKey fallback on server for single-tenant deployments
This commit is contained in:
+10
-2
@@ -37,7 +37,11 @@ export interface HttpServerInstance {
|
||||
* 2. X-OpenProject-Api-Key: <key>
|
||||
* 3. ?apiKey=<key> query parameter
|
||||
*/
|
||||
export function extractApiKey(req: Request, url: URL): string | undefined {
|
||||
export function extractApiKey(
|
||||
req: Request,
|
||||
url: URL,
|
||||
defaultApiKey?: string
|
||||
): string | undefined {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (authHeader) {
|
||||
const match = authHeader.match(/^Bearer\s+(.+)$/i);
|
||||
@@ -56,6 +60,10 @@ export function extractApiKey(req: Request, url: URL): string | undefined {
|
||||
return queryKey.trim();
|
||||
}
|
||||
|
||||
if (defaultApiKey && defaultApiKey.trim().length > 0) {
|
||||
return defaultApiKey.trim();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -192,7 +200,7 @@ export async function startHttpServer(config: AppConfig): Promise<HttpServerInst
|
||||
});
|
||||
}
|
||||
|
||||
const apiKey = extractApiKey(req, url);
|
||||
const apiKey = extractApiKey(req, url, config.apiKey);
|
||||
if (!apiKey) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
|
||||
@@ -243,6 +243,27 @@ describe("Hosted Remote MCP Server (HTTP/SSE)", () => {
|
||||
expect(res.headers.get("access-control-allow-methods")).toContain("GET");
|
||||
});
|
||||
|
||||
test("GET /sse falls back to config.apiKey when configured on server", async () => {
|
||||
const singleTenantServer = await startHttpServer({
|
||||
baseUrl: "https://mock.openproject.example.com",
|
||||
readOnly: true,
|
||||
port: 0,
|
||||
host: "127.0.0.1",
|
||||
apiKey: "server-configured-key",
|
||||
});
|
||||
|
||||
const res = await fetch(`http://127.0.0.1:${singleTenantServer.port}/sse`, {
|
||||
headers: { Accept: "text/event-stream" },
|
||||
});
|
||||
expect(res.status).toBe(200);
|
||||
const reader = res.body?.getReader();
|
||||
const { value } = await reader!.read();
|
||||
const text = new TextDecoder().decode(value);
|
||||
expect(text).toContain("event: endpoint");
|
||||
await reader!.cancel();
|
||||
await singleTenantServer.stop();
|
||||
});
|
||||
|
||||
test("concurrent clients with different API keys maintain isolated sessions", async () => {
|
||||
// Client A
|
||||
const resA = await fetch(`${serverUrl}/sse?apiKey=user-a-secret`, {
|
||||
|
||||
Reference in New Issue
Block a user