Skip to content

Commit a5632bd

Browse files
committed
feat: implement combined demo-check and sign-out endpoint for fresh sign-up flow
1 parent 3075a17 commit a5632bd

2 files changed

Lines changed: 59 additions & 14 deletions

File tree

app/pages/auth/fresh-signup.vue

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,16 @@ const localePath = useLocalePath()
77
88
onMounted(async () => {
99
try {
10-
// Server-side demo check — avoids client-side auth library quirks
11-
const { hasSession, isDemo } = await $fetch('/api/auth/demo-check')
10+
// Single server-side call: checks demo status AND signs out if needed.
11+
// The server deletes the session from the DB and clears auth cookies
12+
// via Set-Cookie headers — no client-side sign-out quirks.
13+
const { action } = await $fetch('/api/auth/demo-fresh-signup', { method: 'POST' })
1214
13-
if (!hasSession) {
14-
window.location.href = localePath('/auth/sign-up')
15-
return
16-
}
17-
18-
if (isDemo) {
19-
// Sign out the demo session via the auth API directly
20-
await $fetch('/api/auth/sign-out', { method: 'POST', body: {} })
21-
// Hard navigate to clear all client-side state (Better Auth atoms, Nuxt caches)
22-
window.location.href = localePath('/auth/sign-up')
15+
if (action === 'dashboard') {
16+
window.location.href = localePath('/dashboard')
2317
}
2418
else {
25-
// Real user — go to dashboard
26-
window.location.href = localePath('/dashboard')
19+
window.location.href = localePath('/auth/sign-up')
2720
}
2821
}
2922
catch {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { eq } from 'drizzle-orm'
2+
import * as schema from '../../database/schema'
3+
4+
/**
5+
* Combined demo-check + sign-out endpoint for the fresh-signup flow.
6+
*
7+
* Called when a marketing-site visitor clicks "Use Cloud". Determines
8+
* whether the existing session belongs to the demo org, and if so,
9+
* deletes the session server-side and clears the auth cookies so the
10+
* browser arrives at sign-up with a clean slate.
11+
*
12+
* Returns { action: 'signup' | 'dashboard' }.
13+
*/
14+
export default defineEventHandler(async (event) => {
15+
const session = await auth.api.getSession({ headers: event.headers })
16+
17+
if (!session) {
18+
return { action: 'signup' }
19+
}
20+
21+
const demoSlug = useRuntimeConfig().public.demoOrgSlug as string
22+
const activeOrgId = (session.session as { activeOrganizationId?: string }).activeOrganizationId
23+
24+
if (!demoSlug || !activeOrgId) {
25+
return { action: 'dashboard' }
26+
}
27+
28+
const [org] = await db
29+
.select({ slug: schema.organization.slug })
30+
.from(schema.organization)
31+
.where(eq(schema.organization.id, activeOrgId))
32+
.limit(1)
33+
34+
if (org?.slug !== demoSlug) {
35+
return { action: 'dashboard' }
36+
}
37+
38+
// ── Demo session — destroy it server-side ──────────────────────
39+
// 1. Remove the session row from the database
40+
await db.delete(schema.session).where(eq(schema.session.id, session.session.id))
41+
42+
// 2. Expire the auth cookies so the browser doesn't keep sending them.
43+
// Better Auth prefixes cookie names with __Secure- over HTTPS.
44+
const isSecure = getRequestURL(event).protocol === 'https:'
45+
const prefix = isSecure ? '__Secure-better-auth' : 'better-auth'
46+
const cookieOpts = { path: '/', ...(isSecure && { secure: true }) }
47+
48+
deleteCookie(event, `${prefix}.session_token`, cookieOpts)
49+
deleteCookie(event, `${prefix}.session_data`, cookieOpts)
50+
51+
return { action: 'signup' }
52+
})

0 commit comments

Comments
 (0)