From e6f4e4579334b347ac51e56528007aaa3e933705 Mon Sep 17 00:00:00 2001 From: NickyDoes Date: Mon, 20 Apr 2026 15:03:22 -0400 Subject: [PATCH] Fix org provisioning: move from signIn to jwt callback signIn fires before DrizzleAdapter creates the user row for OIDC providers, causing FK violation on user_orgs. jwt fires after the adapter, so the user row exists by the time we insert the org. --- web/lib/auth/config.ts | 43 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/web/lib/auth/config.ts b/web/lib/auth/config.ts index 0c780c2..1350c31 100644 --- a/web/lib/auth/config.ts +++ b/web/lib/auth/config.ts @@ -85,28 +85,29 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ signIn: "/login", }, callbacks: { - async signIn({ user }) { - if (!user.id) return false; - const existing = await db - .select({ orgId: userOrgs.orgId }) - .from(userOrgs) - .where(eq(userOrgs.userId, user.id)) - .limit(1); - if (existing.length === 0) { - const displayName = user.name ?? user.email?.split("@")[0] ?? "workspace"; - const slug = `org-${user.id.slice(0, 8)}`; - const [org] = await db - .insert(orgs) - .values({ name: `${displayName}'s workspace`, slug, plan: "free" }) - .returning({ id: orgs.id }); - await db - .insert(userOrgs) - .values({ userId: user.id, orgId: org.id, role: "owner" }); - } - return true; - }, + // jwt fires after the adapter has written the user row, making it the + // correct place to provision the default org. signIn fires before the + // adapter for OIDC providers, so user_id FK constraints fail there. async jwt({ token, user }) { - if (user?.id) token.sub = user.id; + if (user?.id) { + token.sub = user.id; + const existing = await db + .select({ orgId: userOrgs.orgId }) + .from(userOrgs) + .where(eq(userOrgs.userId, user.id)) + .limit(1); + if (existing.length === 0) { + const displayName = user.name ?? user.email?.split("@")[0] ?? "workspace"; + const slug = `org-${user.id.slice(0, 8)}`; + const [org] = await db + .insert(orgs) + .values({ name: `${displayName}'s workspace`, slug, plan: "free" }) + .returning({ id: orgs.id }); + await db + .insert(userOrgs) + .values({ userId: user.id, orgId: org.id, role: "owner" }); + } + } return token; }, async session({ session, token }) {