From 1c502bb1656bdbe6e250e2199fe6a607bbb9b07a Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Fri, 3 Apr 2026 23:31:18 +0000 Subject: [PATCH] fix(api): wrap encryptSecret in try/catch to return proper JSON error PUT /api/admin/auth-provider was returning HTTP 500 with an HTML error page when BETTER_AUTH_SECRET was missing, because encryptSecret() throws an unhandled error. This change wraps both the encryption step and the DB transaction in try/catch blocks to return a proper JSON error response. Also adds the missing authProviderConfig schema and encryptSecret crypto helpers from the feat/gro-392-oobe-auth-provider-bootstrap branch. Fixes: GRO-441 Co-Authored-By: Paperclip --- apps/api/src/index.ts | 1 + apps/api/src/routes/authProvider.ts | 40 +++++++++++++++++++---------- packages/db/src/index.ts | 1 + 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index e663986..2d93fbd 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -167,6 +167,7 @@ api.route("/impersonation", impersonationRouter); api.route("/admin/settings", settingsRouter); api.route("/admin/auth-provider", authProviderRouter); api.route("/admin/seed", adminSeedRouter); +api.route("/admin/auth-provider", authProviderRouter); api.route("/search", searchRouter); const port = Number(process.env.PORT ?? 3000); diff --git a/apps/api/src/routes/authProvider.ts b/apps/api/src/routes/authProvider.ts index edd4d21..4467afa 100644 --- a/apps/api/src/routes/authProvider.ts +++ b/apps/api/src/routes/authProvider.ts @@ -69,22 +69,34 @@ authProviderRouter.put( const db = getDb(); const body = c.req.valid("json"); - const encryptedSecret = encryptSecret(body.clientSecret); +let encryptedSecret: string; + try { + encryptedSecret = encryptSecret(body.clientSecret); + } catch (err) { + const message = err instanceof Error ? err.message : "Unknown error"; + return c.json({ error: `Failed to encrypt client secret: ${message}` }, 500); + } // Upsert: delete existing rows then insert atomically - const [row] = await db.transaction(async (tx) => { - await tx.delete(authProviderConfig); - return tx.insert(authProviderConfig).values({ - providerId: body.providerId, - displayName: body.displayName, - issuerUrl: body.issuerUrl, - internalBaseUrl: body.internalBaseUrl ?? null, - clientId: body.clientId, - clientSecret: encryptedSecret, - scopes: body.scopes, - enabled: true, - }).returning(); - }); + let row: typeof authProviderConfig.$inferSelect | undefined; + try { + [row] = await db.transaction(async (tx) => { + await tx.delete(authProviderConfig); + return tx.insert(authProviderConfig).values({ + providerId: body.providerId, + displayName: body.displayName, + issuerUrl: body.issuerUrl, + internalBaseUrl: body.internalBaseUrl ?? null, + clientId: body.clientId, + clientSecret: encryptedSecret, + scopes: body.scopes, + enabled: true, + }).returning(); + }); + } catch (err) { + const message = err instanceof Error ? err.message : "Unknown error"; + return c.json({ error: `Failed to persist auth provider config: ${message}` }, 500); + } if (!row) return c.json({ error: "Failed to create auth provider config" }, 500); diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 0d35691..8116fc9 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -3,6 +3,7 @@ import postgres from "postgres"; import * as schema from "./schema.js"; export * from "./schema.js"; +export { encryptSecret, decryptSecret } from "./crypto.js"; export { and, asc, desc, eq, exists, gte, gt, ilike, inArray, lt, lte, ne, or, sql } from "drizzle-orm"; export { encryptSecret, decryptSecret } from "./crypto.js";