From 216888da0e7b77c400d0262a2e4950dbef363698 Mon Sep 17 00:00:00 2001 From: Anand Pant Date: Thu, 21 May 2026 01:35:28 -0500 Subject: [PATCH] fix(auth): accept active WorkOS client during Convex deploy --- packages/backend/convex/auth.config.test.ts | 29 +++++++++++++++++ packages/backend/convex/auth.config.ts | 36 +++++++++++++-------- 2 files changed, 52 insertions(+), 13 deletions(-) create mode 100644 packages/backend/convex/auth.config.test.ts diff --git a/packages/backend/convex/auth.config.test.ts b/packages/backend/convex/auth.config.test.ts new file mode 100644 index 0000000..3b9c396 --- /dev/null +++ b/packages/backend/convex/auth.config.test.ts @@ -0,0 +1,29 @@ +import { beforeAll, describe, expect, test } from "vitest"; + +let buildWorkOsClientIds: (primaryClientId: string) => string[]; + +beforeAll(async () => { + process.env.WORKOS_CLIENT_ID = "client_current"; + ({ buildWorkOsClientIds } = await import("./auth.config")); +}); + +describe("buildWorkOsClientIds", () => { + test("keeps the primary client id first", () => { + expect(buildWorkOsClientIds("client_current")).toEqual(["client_current"]); + }); + + test("accepts current production tokens when Convex still has the preview client", () => { + expect(buildWorkOsClientIds("client_01KFPXKM905BYDQY5Q7BFJN409")).toEqual([ + "client_01KFPXKM905BYDQY5Q7BFJN409", + "client_01KG0NPZN3AWXNTRHC58VAPVW2", + ]); + }); + + test("accepts preview and production tokens when Convex still has the legacy preview client", () => { + expect(buildWorkOsClientIds("client_01KG0NZ3QX0AJQE87CKZC74YXQ")).toEqual([ + "client_01KG0NZ3QX0AJQE87CKZC74YXQ", + "client_01KFPXKM905BYDQY5Q7BFJN409", + "client_01KG0NPZN3AWXNTRHC58VAPVW2", + ]); + }); +}); diff --git a/packages/backend/convex/auth.config.ts b/packages/backend/convex/auth.config.ts index 1c82b7a..e1b41f2 100644 --- a/packages/backend/convex/auth.config.ts +++ b/packages/backend/convex/auth.config.ts @@ -8,20 +8,30 @@ if (!clientId) { const previewWorkOsClientId = "client_01KFPXKM905BYDQY5Q7BFJN409"; const legacyPreviewAuthConfigClientId = "client_01KG0NZ3QX0AJQE87CKZC74YXQ"; +const productionWorkOsClientId = "client_01KG0NPZN3AWXNTRHC58VAPVW2"; -const clientIds = Array.from( - new Set( - [ - clientId, - // Convex auth config only permits env vars already set in Convex. - // During preview deploys, auth config currently sees the legacy client - // while Vercel/WorkOS mint tokens for the newer preview client. - clientId === legacyPreviewAuthConfigClientId - ? previewWorkOsClientId - : null, - ].filter((value): value is string => Boolean(value)) - ) -); +export function buildWorkOsClientIds(primaryClientId: string): string[] { + return Array.from( + new Set( + [ + primaryClientId, + // Convex auth config can see the previously stored client during the + // same deploy that refreshes WorkOS/Vercel credentials. Keep the + // active handoff clients valid so first deploys do not reject fresh + // AuthKit tokens. + primaryClientId === legacyPreviewAuthConfigClientId + ? previewWorkOsClientId + : null, + primaryClientId === legacyPreviewAuthConfigClientId || + primaryClientId === previewWorkOsClientId + ? productionWorkOsClientId + : null, + ].filter((value): value is string => Boolean(value)) + ) + ); +} + +const clientIds = buildWorkOsClientIds(clientId); export default { providers: clientIds.flatMap((currentClientId) => {