|
| 1 | +import { eq } from 'drizzle-orm' |
| 2 | +import * as schema from '../../database/schema' |
| 3 | + |
| 4 | +/** |
| 5 | + * Demo-aware signup redirect endpoint. |
| 6 | + * |
| 7 | + * Called via full browser navigation (not $fetch) when a marketing-site |
| 8 | + * visitor clicks "Use Cloud". If the browser carries a demo-org session |
| 9 | + * cookie, the session is destroyed server-side and the auth cookies are |
| 10 | + * expired before redirecting to /auth/sign-up with a clean slate. |
| 11 | + * |
| 12 | + * Using a GET → 302 redirect (instead of $fetch → JSON) guarantees the |
| 13 | + * browser processes Set-Cookie headers during native navigation, which |
| 14 | + * is the only fully reliable way to clear HttpOnly cookies. |
| 15 | + */ |
| 16 | +export default defineEventHandler(async (event) => { |
| 17 | + const session = await auth.api.getSession({ headers: event.headers }) |
| 18 | + |
| 19 | + if (!session) { |
| 20 | + return sendRedirect(event, '/auth/sign-up') |
| 21 | + } |
| 22 | + |
| 23 | + const demoSlug = useRuntimeConfig().public.demoOrgSlug as string |
| 24 | + const activeOrgId = (session.session as { activeOrganizationId?: string }).activeOrganizationId |
| 25 | + |
| 26 | + if (!demoSlug || !activeOrgId) { |
| 27 | + // Real user with an active org — send to dashboard |
| 28 | + return sendRedirect(event, '/dashboard') |
| 29 | + } |
| 30 | + |
| 31 | + const [org] = await db |
| 32 | + .select({ slug: schema.organization.slug }) |
| 33 | + .from(schema.organization) |
| 34 | + .where(eq(schema.organization.id, activeOrgId)) |
| 35 | + .limit(1) |
| 36 | + |
| 37 | + if (org?.slug !== demoSlug) { |
| 38 | + // Real org — send to dashboard |
| 39 | + return sendRedirect(event, '/dashboard') |
| 40 | + } |
| 41 | + |
| 42 | + // ── Demo session — destroy it server-side ────────────────────── |
| 43 | + |
| 44 | + // 1. Remove the session row from the database so the token is invalid |
| 45 | + // even if a cookie somehow survives. |
| 46 | + await db.delete(schema.session).where(eq(schema.session.id, session.session.id)) |
| 47 | + |
| 48 | + // 2. Expire auth cookies. Better Auth prefixes with __Secure- when |
| 49 | + // baseURL starts with https://. Behind a reverse proxy (Railway, |
| 50 | + // Cloudflare) the request protocol is http even in production, |
| 51 | + // so we clear BOTH variants to guarantee removal. |
| 52 | + for (const prefix of ['better-auth', '__Secure-better-auth']) { |
| 53 | + for (const name of ['session_token', 'session_data']) { |
| 54 | + deleteCookie(event, `${prefix}.${name}`, { path: '/' }) |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + return sendRedirect(event, '/auth/sign-up') |
| 59 | +}) |
0 commit comments