From b3740c95673e863a11194eb4bd6062bfb7fe9876 Mon Sep 17 00:00:00 2001 From: Afreen Sikandara Date: Tue, 26 May 2026 10:16:51 +0800 Subject: [PATCH 1/2] Fix auth for old fhir server --- services/trex/core/server/env.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/services/trex/core/server/env.ts b/services/trex/core/server/env.ts index 2463635f19..3e8f3524fc 100644 --- a/services/trex/core/server/env.ts +++ b/services/trex/core/server/env.ts @@ -53,6 +53,7 @@ export const publicURLs = [ '^/prefect/docs$', '^/openapi.json$', '^/fhir-server/healthcheck$', + '^/fhir-server/.*$', '^/gateway/api/dataset/shiny-live/.*$' ] From 6f9fa844d6ffb539b7819dff346d5e193e706a9e Mon Sep 17 00:00:00 2001 From: Afreen Sikandara Date: Thu, 4 Jun 2026 14:41:12 +0800 Subject: [PATCH 2/2] Add fhir server in trex image and auth --- services/trex/Dockerfile.v2 | 2 ++ services/trex/core/server/auth/authn.ts | 32 ++++++++++++++++++++++--- services/trex/core/server/env.ts | 1 - 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/services/trex/Dockerfile.v2 b/services/trex/Dockerfile.v2 index 67b1cc62aa..a07d436f5d 100644 --- a/services/trex/Dockerfile.v2 +++ b/services/trex/Dockerfile.v2 @@ -116,6 +116,8 @@ RUN --mount=type=secret,id=PLUGINS_REGISTRY set -eu; \ echo "@data2evidence:registry=$REG" > .npmrc; \ npm install @data2evidence/d2e-atlas --no-save; \ mv "node_modules/@data2evidence/d2e-atlas" /usr/src/bundled-plugins/d2e-atlas; \ + npm install @data2evidence/d2e-fhir-server --no-save; \ + mv "node_modules/@data2evidence/d2e-fhir-server" /usr/src/bundled-plugins/d2e-fhir-server; \ rm -rf "$WORK" ENV PLUGINS_DEV_PATH=/usr/src/bundled-plugins:/usr/src/plugins diff --git a/services/trex/core/server/auth/authn.ts b/services/trex/core/server/auth/authn.ts index 14617755be..ffe3b3fca4 100644 --- a/services/trex/core/server/auth/authn.ts +++ b/services/trex/core/server/auth/authn.ts @@ -44,6 +44,23 @@ export async function authn(c: Context, next: Function) { return; } + const isFhirServerRoute = c.req.path.startsWith("/fhir-server/"); + if (isFhirServerRoute) { + const token = extractFhirCookieToken(c); + if (!token) { + return new Response("Unauthorized", { status: 401 }); + } + try { + await jwtVerify(token, JWKS); + } catch (err: any) { + logger.error(`authn: fhir-server token validation failed: ${err}`); + return new Response("Authentication Token not valid", { status: 401 }); + } + c.set("logtoSubject", getTokenSubject(token)); + await next(); + return; + } + const token = extractToken(c); if (!token) { @@ -61,6 +78,18 @@ export async function authn(c: Context, next: Function) { await next(); } +function extractFhirCookieToken(c: Context): string | null { + const cookieHeader = c.req.header("cookie") ?? c.req.raw.headers.get("cookie") ?? ""; + for (const cookie of cookieHeader.split(";")) { + const trimmed = cookie.trim(); + if (trimmed.startsWith("fhirtoken=")) { + const val = trimmed.slice("fhirtoken=".length).trim(); + return val.startsWith("Bearer ") ? val.slice(7) : val || null; + } + } + return null; +} + function extractToken(c: Context): string | null { const regex = /\b(Bearer|bearer|token)\b/; @@ -79,9 +108,6 @@ function extractToken(c: Context): string | null { for (const cookie of cookies) { if (cookie.startsWith("authtoken=")) { return cookie.split("=")[1]; - } else if (cookie.startsWith("fhirtoken=")) { - const val = cookie.split("=")[1]; - return val.split(" ")[1] || null; } } } diff --git a/services/trex/core/server/env.ts b/services/trex/core/server/env.ts index e14f885ed8..3d74a9ff42 100644 --- a/services/trex/core/server/env.ts +++ b/services/trex/core/server/env.ts @@ -53,7 +53,6 @@ export const publicURLs = [ '^/prefect/docs$', '^/openapi.json$', '^/fhir-server/healthcheck$', - '^/fhir-server/.*$', '^/gateway/api/dataset/shiny-live/.*$' ]