From b78e45b5c5dbd1f7264157cee1f2bfe20bf3a6d6 Mon Sep 17 00:00:00 2001 From: The Dogfather Date: Sat, 28 Mar 2026 01:23:10 +0000 Subject: [PATCH] =?UTF-8?q?fix(auth):=20dev=20login=20403=20=E2=80=94=20re?= =?UTF-8?q?solve=20staff=20by=20id,=20not=20oidcSub=20(GRO-150)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DevLoginSelector stores the staff database id in localStorage and sends it as X-Dev-User-Id. The resolveStaffMiddleware incorrectly looked up staff by oidcSub instead of id, causing all API endpoints to return 403 for every user in dev mode. Co-Authored-By: Paperclip --- apps/api/src/__tests__/rbac.test.ts | 2 +- apps/api/src/middleware/rbac.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/api/src/__tests__/rbac.test.ts b/apps/api/src/__tests__/rbac.test.ts index b052507..d8c26bf 100644 --- a/apps/api/src/__tests__/rbac.test.ts +++ b/apps/api/src/__tests__/rbac.test.ts @@ -165,7 +165,7 @@ describe("resolveStaffMiddleware", () => { }); const res = await app.request("/test", { - headers: { "X-Dev-User-Id": GROOMER.oidcSub! }, + headers: { "X-Dev-User-Id": GROOMER.id }, }); expect(res.status).toBe(200); expect(capturedStaff!.role).toBe("groomer"); diff --git a/apps/api/src/middleware/rbac.ts b/apps/api/src/middleware/rbac.ts index 24a6753..98d9405 100644 --- a/apps/api/src/middleware/rbac.ts +++ b/apps/api/src/middleware/rbac.ts @@ -41,11 +41,11 @@ export const resolveStaffMiddleware: MiddlewareHandler = async ( await next(); return; } - // Treat X-Dev-User-Id as the oidcSub + // Treat X-Dev-User-Id as the staff database id (the frontend stores staff.id) const [row] = await db .select() .from(staff) - .where(eq(staff.oidcSub, devUserId)); + .where(eq(staff.id, devUserId)); if (!row) { return c.json( { error: "Forbidden: no staff record found for X-Dev-User-Id" }, -- 2.52.0