From 98508af01f9732c2a45592e3e448782716873e13 Mon Sep 17 00:00:00 2001 From: "groombook-engineer[bot]" <3141748+groombook-engineer[bot]@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:01:33 +0000 Subject: [PATCH] fix(oobe): add test connection endpoint and fix EOF newline (GRO-392) - Add POST /api/setup/auth-provider/test endpoint for OOBE test connection - Guard with same !superUser check as bootstrap endpoint - Update SetupWizard to call /api/setup/auth-provider/test instead of /api/admin/auth-provider/test (which requires auth session) - Add trailing newline at EOF in setup.ts Co-Authored-By: Paperclip --- apps/api/src/routes/setup.ts | 46 +++++++++++++++++++++++++++++- apps/web/src/pages/SetupWizard.jsx | 2 +- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/apps/api/src/routes/setup.ts b/apps/api/src/routes/setup.ts index 5869489..3bb470f 100644 --- a/apps/api/src/routes/setup.ts +++ b/apps/api/src/routes/setup.ts @@ -178,4 +178,48 @@ setupRouter.post("/auth-provider", zValidator("json", authProviderBootstrapSchem createdAt: row.createdAt, updatedAt: row.updatedAt, }, 201); -}); \ No newline at end of file +}); + +/** + * POST /api/setup/auth-provider/test + * Unauthenticated endpoint to validate an OIDC provider configuration during OOBE. + * Fetches the OIDC discovery document to confirm the issuer is reachable. + * Only available when needsSetup is true (no super user = fresh install). + */ +setupRouter.post("/auth-provider/test", zValidator("json", authProviderBootstrapSchema), async (c) => { + const db = getDb(); + + // Guard: only allow during fresh install (no super user yet) + const [superUser] = await db + .select({ id: staff.id }) + .from(staff) + .where(eq(staff.isSuperUser, true)) + .limit(1); + + if (superUser) { + return c.json({ ok: false, error: "Setup has already been completed." }, 403); + } + + const body = c.req.valid("json"); + + // Determine the discovery URL + const discoveryUrl = body.internalBaseUrl + ? `${body.internalBaseUrl}/application/o/.well-known/openid-configuration` + : `${body.issuerUrl}/.well-known/openid-configuration`; + + try { + const res = await fetch(discoveryUrl, { method: "GET" }); + if (!res.ok) { + return c.json({ + ok: false, + error: `OIDC discovery failed (HTTP ${res.status}). Check your Issuer URL and Internal Base URL.`, + }); + } + return c.json({ ok: true }); + } catch (e) { + return c.json({ + ok: false, + error: "Could not reach the OIDC provider. Check your Issuer URL and network connectivity.", + }); + } +}); diff --git a/apps/web/src/pages/SetupWizard.jsx b/apps/web/src/pages/SetupWizard.jsx index 2d4de2d..aaaf269 100644 --- a/apps/web/src/pages/SetupWizard.jsx +++ b/apps/web/src/pages/SetupWizard.jsx @@ -82,7 +82,7 @@ export function SetupWizard() { setTestingConnection(true); setTestResult(null); try { - const res = await fetch("/api/admin/auth-provider/test", { + const res = await fetch("/api/setup/auth-provider/test", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({