Overview
Authentication with BetterAuth and Convex
StarterApp pairs BetterAuth with Convex so that sign-in, session storage, and organisation state all stay in sync. Most of the heavy lifting is hidden behind simple helpers, so product teams can focus on experience instead of wiring.
High level takeaway
Use the shared helpers (getCurrentSession, requireUser, useSession) and the stack handles cookies, redirects, and organisation state for you.
How the pieces fit together
-
BetterAuth configuration (
convex/lib/auth.ts)
Defines secure cookies, optional Google sign-in, and the username/password toggle that can be disabled withDISABLE_USERNAME_PASSWORD_AUTH. -
Convex lifecycle (
convex/auth.ts)
Triggers keep BetterAuth records synced with Convex tables, ensure every user has an active organisation, and expose thegetCurrentUserquery used across the app. -
Post-login handshake (
apps/dashboard/app/auth/after/route.ts)
After an OAuth or password sign-in, this route waits until Convex confirms the user and organisation data are ready, then redirects to the requested page. -
Server helpers (
packages/app-shell/src/lib/auth/server.ts)
getCurrentSession()returns the current user ornull.requireUser()redirects to/sign-inwhen the session is missing. These power pages, layouts, and server actions. -
Client helpers (
@workspace/auth/client)
useSession()andsignIn/signOutare available everywhere under the dashboard thanks to theConvexBetterAuthProvider.
What happens after sign-in
BetterAuth stores an HttpOnly cookie and Convex triggers create or refresh the user record (including a personal workspace on first visit).
The /auth/after route checks with Convex until the user record is ready, then sends the person to their target page (for example /dashboard).
Server components call getCurrentSession() or requireUser(), while client components use useSession() or useQuery(api.auth.getCurrentUser) for live updates.
Security highlights
- HttpOnly cookies with the production-safe
__Host-sessionname - Same-origin CSRF checks on every write (API routes, Convex HTTP handlers, and dashboard pages)
- Mandatory cache settings on protected routes:
revalidate = 0,dynamic = "force-dynamic",fetchCache = "force-no-store" - Hardened JSON helpers (
secureUserJson,secureErrorJson) that add security headers and hide sensitive details /api/auth/*runs on the Node runtime so headers and caching stay under explicit control
Where to look in the repo
Prop
Type
Import with care
Always import createAuth from convex/lib/auth. Importing it from convex/http.ts brings in router side effects that break server components.
Support for AI & new teammates
llms/AUTH_PATTERNS.md– quick reference for token flow, cache settings, and identity helpers.llms/templates/– ready-to-use patterns for protected API routes, Convex functions, and server components.llms/SECURITY.md– checklist covering CSRF enforcement, secure responses, and rate limiting.
Using these guides keeps everyone aligned with the production-ready defaults.
Related Documentation
Session Management
How server, client, and API surfaces read session data
Organizations
Understand personal workspaces, shared orgs, and active-org sync
Protected Routes
Patterns for guarding layouts, pages, and API routes
OAuth Providers
Configure Google sign-in and extend to other providers
AI Patterns
Context engineering tips for authentication tasks