From b1f6780166aebd965b436141f01f940f5ab663d3 Mon Sep 17 00:00:00 2001 From: Nicholai Date: Sun, 15 Feb 2026 22:45:34 -0700 Subject: [PATCH] fix(auth): delete demo cookie in middleware (#93) The demo cookie deletion in getCurrentUser() was a no-op from Server Component context (cookies().delete() only works in Server Actions and Route Handlers). The cookie persisted for its full 24h lifetime, causing middleware to short-circuit auth checks even when a real WorkOS session existed. - Middleware: real session now takes priority over demo cookie, stale cookie actively deleted via Set-Cookie on response - auth.ts: remove early demo-first check and dead deletion code, WorkOS session checked before demo fallback - /demo route: clear compass-active-org so demo doesn't inherit a real user's workspace selection Co-authored-by: Nicholai --- src/app/demo/route.ts | 3 +++ src/lib/auth.ts | 20 ++------------------ src/middleware.ts | 19 +++++++++++++++---- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/app/demo/route.ts b/src/app/demo/route.ts index 4222112..6c90aa7 100644 --- a/src/app/demo/route.ts +++ b/src/app/demo/route.ts @@ -10,5 +10,8 @@ export async function GET() { path: "/", maxAge: 60 * 60 * 24, // 24 hours }) + // clear stale org preference so demo doesn't inherit + // a real user's last-active workspace + cookieStore.delete("compass-active-org") redirect("/dashboard") } diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 9fcecda..2c6d597 100755 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -53,15 +53,6 @@ export function toSidebarUser(user: AuthUser): SidebarUser { export async function getCurrentUser(): Promise { try { - // check for demo session cookie first - try { - const cookieStore = await cookies() - const isDemoSession = cookieStore.get("compass-demo")?.value === "true" - if (isDemoSession) return DEMO_USER - } catch { - // cookies() may throw in non-request contexts - } - // check if workos is configured const isWorkOSConfigured = process.env.WORKOS_API_KEY && @@ -115,15 +106,8 @@ export async function getCurrentUser(): Promise { return null } - // real session exists -- clear stale demo cookie if present - try { - const cookieStore = await cookies() - if (cookieStore.get("compass-demo")) { - cookieStore.delete("compass-demo") - } - } catch { - // cookies() may throw in non-request contexts - } + // demo cookie cleanup handled by middleware (can't delete + // cookies from Server Components -- only actions/routes) const workosUser = session.user diff --git a/src/middleware.ts b/src/middleware.ts index d5e80b2..c45a86a 100755 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -41,9 +41,18 @@ export default async function middleware(request: NextRequest) { return handleAuthkitHeaders(request, headers) } - // demo sessions bypass auth - const isDemoSession = request.cookies.get("compass-demo")?.value === "true" - if (isDemoSession) { + const hasDemoCookie = + request.cookies.get("compass-demo")?.value === "true" + + // real session trumps demo cookie -- clear the stale cookie + if (session.user && hasDemoCookie) { + const response = handleAuthkitHeaders(request, headers) + response.cookies.delete("compass-demo") + return response + } + + // demo sessions bypass auth (no real session present) + if (hasDemoCookie) { return handleAuthkitHeaders(request, headers) } @@ -51,7 +60,9 @@ export default async function middleware(request: NextRequest) { if (!session.user) { const loginUrl = new URL("/login", request.url) loginUrl.searchParams.set("from", pathname) - return handleAuthkitHeaders(request, headers, { redirect: loginUrl.toString() }) + return handleAuthkitHeaders(request, headers, { + redirect: loginUrl.toString(), + }) } // authenticated - continue with authkit headers