fix(auth): demo cookie no longer overrides real session (#91)

* feat(security): add multi-tenancy isolation and demo mode

Add org-scoped data isolation across all server actions to
prevent cross-org data leakage. Add read-only demo mode with
mutation guards on all write endpoints.

Multi-tenancy:
- org filter on executeDashboardQueries (all query types)
- org boundary checks on getChannel, joinChannel
- searchMentionableUsers derives org from session
- getConversationUsage scoped to user, not org-wide for admins
- organizations table, members, org switcher component

Demo mode:
- /demo route sets strict sameSite cookie
- isDemoUser guards on all mutation server actions
- demo banner, CTA dialog, and gate components
- seed script for demo org data

Also: exclude scripts/ from tsconfig (fixes build), add
multi-tenancy architecture documentation.

* fix(auth): real session takes priority over demo cookie

The demo cookie was checked unconditionally before WorkOS auth,
so logging in with real credentials after visiting /demo still
returned the demo user. Now getCurrentUser() tries WorkOS first
and only falls back to the demo cookie when no real session
exists. Clears the stale cookie on real login.

---------

Co-authored-by: Nicholai <nicholaivogelfilms@gmail.com>
This commit is contained in:
Nicholai 2026-02-15 22:21:54 -07:00 committed by GitHub
parent ad2f0c0b9c
commit c75b043259
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -69,6 +69,16 @@ export async function getCurrentUser(): Promise<AuthUser | null> {
!process.env.WORKOS_API_KEY.includes("placeholder")
if (!isWorkOSConfigured) {
// check demo cookie when WorkOS isn't available
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
}
// return mock user for development
return {
id: "dev-user-1",
@ -89,8 +99,31 @@ export async function getCurrentUser(): Promise<AuthUser | null> {
}
}
// WorkOS is configured -- try real auth first
const session = await withAuth()
if (!session || !session.user) return null
if (!session || !session.user) {
// no real session; fall back to demo cookie
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
}
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
}
const workosUser = session.user