From 0953d6cb329aad663fc55e96c785a6bcf9ea3e06 Mon Sep 17 00:00:00 2001 From: "groombook-engineer[bot]" <3141748+groombook-engineer[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 02:36:29 +0000 Subject: [PATCH] fix(api): move needsSetup guard before Zod parsing in setup endpoints POST /api/setup/auth-provider and POST /api/setup/auth-provider/test were returning 400 (Zod validation) instead of 403 when needsSetup was false, because zValidator middleware ran before the route handler body. Now manually parse the body after the needsSetup guard so 403 fires immediately for post-setup requests. Co-Authored-By: Paperclip --- apps/api/src/routes/setup.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/api/src/routes/setup.ts b/apps/api/src/routes/setup.ts index 775ab1f..c020fb8 100644 --- a/apps/api/src/routes/setup.ts +++ b/apps/api/src/routes/setup.ts @@ -123,7 +123,7 @@ const authProviderTestSchema = z.object({ * Rate-limited by the API gateway; additionally restricted to first-time setup only. * After setup completes, this endpoint permanently returns 403. */ -setupRouter.post("/auth-provider", zValidator("json", authProviderBootstrapSchema), async (c) => { +setupRouter.post("/auth-provider", async (c) => { const db = getDb(); // Guard: only allow during fresh install (no super user yet) @@ -149,7 +149,7 @@ setupRouter.post("/auth-provider", zValidator("json", authProviderBootstrapSchem return c.json({ error: "Auth provider is already configured." }, 409); } - const body = c.req.valid("json"); + const body = authProviderBootstrapSchema.parse(c.req.valid("json")); // Encrypt clientSecret before storing const encryptedSecret = encryptSecret(body.clientSecret); @@ -192,7 +192,7 @@ setupRouter.post("/auth-provider", zValidator("json", authProviderBootstrapSchem * 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", authProviderTestSchema), async (c) => { +setupRouter.post("/auth-provider/test", async (c) => { const db = getDb(); // Guard: only allow during fresh install (no super user yet) @@ -206,7 +206,7 @@ setupRouter.post("/auth-provider/test", zValidator("json", authProviderTestSchem return c.json({ ok: false, error: "Setup has already been completed." }, 403); } - const body = c.req.valid("json"); + const body = authProviderTestSchema.parse(c.req.valid("json")); // Determine the discovery URL const discoveryUrl = body.internalBaseUrl