From 711981e6f34e38da20b38b1348f10b8491e9dc5a Mon Sep 17 00:00:00 2001 From: Flea Flicker Date: Sun, 5 Apr 2026 14:30:25 +0000 Subject: [PATCH] fix(api): auto-link staff to Better-Auth user via email on first SSO login (GRO-480) When a staff record exists with a matching email but no userId (e.g. seed data or admin UI-created records), resolveStaffMiddleware now auto-links it to the Better-Auth user record on first SSO login instead of returning 403. Safety: only links when userId IS NULL, never overwrites an existing link. Email matching is safe since it comes from the trusted SSO provider (Authentik). Staff emails are unique by schema. Co-Authored-By: Paperclip --- apps/api/src/middleware/rbac.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/apps/api/src/middleware/rbac.ts b/apps/api/src/middleware/rbac.ts index d5e764e..9075ee9 100644 --- a/apps/api/src/middleware/rbac.ts +++ b/apps/api/src/middleware/rbac.ts @@ -1,5 +1,6 @@ import type { MiddlewareHandler } from "hono"; -import { eq, getDb, staff } from "@groombook/db"; +import { isNull } from "drizzle-orm"; +import { and, eq, getDb, staff } from "@groombook/db"; export type StaffRole = "groomer" | "receptionist" | "manager"; export type StaffRow = typeof staff.$inferSelect; @@ -89,6 +90,25 @@ export const resolveStaffMiddleware: MiddlewareHandler = async ( .from(staff) .where(eq(staff.oidcSub, jwt.sub)); if (!fallbackRow) { + // Auto-link: staff record exists with matching email but no userId — link it now + if (jwt.email) { + const [linkedStaff] = await db + .select() + .from(staff) + .where(and(eq(staff.email, jwt.email), isNull(staff.userId))); + if (linkedStaff) { + await db + .update(staff) + .set({ userId: jwt.sub }) + .where(eq(staff.id, linkedStaff.id)); + console.log( + `[rbac] Auto-linked staff ${linkedStaff.id} to Better-Auth user ${jwt.sub} via email ${jwt.email}` + ); + c.set("staff", linkedStaff); + await next(); + return; + } + } return c.json( { error: "Forbidden: no staff record found for authenticated user" }, 403