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 <nicholaivogelfilms@gmail.com>
This commit is contained in:
Nicholai 2026-02-15 22:45:34 -07:00 committed by GitHub
parent c75b043259
commit b1f6780166
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 22 deletions

View File

@ -10,5 +10,8 @@ export async function GET() {
path: "/", path: "/",
maxAge: 60 * 60 * 24, // 24 hours 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") redirect("/dashboard")
} }

View File

@ -53,15 +53,6 @@ export function toSidebarUser(user: AuthUser): SidebarUser {
export async function getCurrentUser(): Promise<AuthUser | null> { export async function getCurrentUser(): Promise<AuthUser | null> {
try { 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 // check if workos is configured
const isWorkOSConfigured = const isWorkOSConfigured =
process.env.WORKOS_API_KEY && process.env.WORKOS_API_KEY &&
@ -115,15 +106,8 @@ export async function getCurrentUser(): Promise<AuthUser | null> {
return null return null
} }
// real session exists -- clear stale demo cookie if present // demo cookie cleanup handled by middleware (can't delete
try { // cookies from Server Components -- only actions/routes)
const cookieStore = await cookies()
if (cookieStore.get("compass-demo")) {
cookieStore.delete("compass-demo")
}
} catch {
// cookies() may throw in non-request contexts
}
const workosUser = session.user const workosUser = session.user

View File

@ -41,9 +41,18 @@ export default async function middleware(request: NextRequest) {
return handleAuthkitHeaders(request, headers) return handleAuthkitHeaders(request, headers)
} }
// demo sessions bypass auth const hasDemoCookie =
const isDemoSession = request.cookies.get("compass-demo")?.value === "true" request.cookies.get("compass-demo")?.value === "true"
if (isDemoSession) {
// 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) return handleAuthkitHeaders(request, headers)
} }
@ -51,7 +60,9 @@ export default async function middleware(request: NextRequest) {
if (!session.user) { if (!session.user) {
const loginUrl = new URL("/login", request.url) const loginUrl = new URL("/login", request.url)
loginUrl.searchParams.set("from", pathname) loginUrl.searchParams.set("from", pathname)
return handleAuthkitHeaders(request, headers, { redirect: loginUrl.toString() }) return handleAuthkitHeaders(request, headers, {
redirect: loginUrl.toString(),
})
} }
// authenticated - continue with authkit headers // authenticated - continue with authkit headers