StarterApp Docs
Authentication

Sessions

Understand how session data flows through StarterApp

BetterAuth stores sessions in secure cookies; Convex keeps the user document and organisation state in sync. StarterApp exposes the result through a few predictable helpers so you can read session information wherever you are working.

One concept, three touchpoints

Use getCurrentSession() on the server, useSession() on the client, and auth.api.getSession() inside API routes. They all describe the same signed-in user.

Server-side access

  • getCurrentSession() (from packages/app-shell/src/lib/auth/server.ts) returns the current user or null. Use it when you want to show different content to guests.
  • requireUser() redirects unauthenticated visitors to /sign-in. Reach for it in protected layouts and pages.
  • Both helpers automatically fetch the richer Convex user record, including active organisation details.

Remember: protected layouts and pages must export the cache killers:

export const revalidate = 0;
export const dynamic = "force-dynamic";
export const fetchCache = "force-no-store";

These exports prevent Next.js from caching personalised data.

Client-side access

  • Wrap the dashboard in ConvexBetterAuthProvider (already done in apps/dashboard/app/providers.tsx).
  • Call useSession() to get { data, isPending }. While isPending is true, the hook is still resolving the session.
  • Prefer useQuery(api.auth.getCurrentUser) when you need live updates (for example, switching organisations or editing profile data).

API routes and server actions

  • Import auth from @workspace/auth/server and call auth.api.getSession({ headers: await headers() }).
  • Combine it with CSRF checks (assertOrigin, assertFetchMetadata) before writing data.
  • Use secureUserJson for successful responses and secureErrorJson for errors so security headers stay consistent.

Session lifecycle (behind the scenes)

  1. User signs in through Google or the credential form. BetterAuth creates an HttpOnly cookie.
  2. Convex triggers ensure the user record exists, create a personal workspace if necessary, and store the active organisation on the user document.
  3. The /auth/after route waits until Convex reports the setup is complete, then redirects to the requested page.
  4. Subsequent requests read session data through the helpers listed above. Sessions refresh automatically after 24 hours of activity and expire after seven days of inactivity.

Quick troubleshooting checklist

  • getCurrentSession() returns null even after sign-in
    → Check that /auth/after is reachable (no ad blockers) and that the Convex deployment has matching BetterAuth env vars.

  • useSession() stays in a loading state
    → Confirm the dashboard is wrapped in ConvexBetterAuthProvider and that the Convex client URL is configured (NEXT_PUBLIC_CONVEX_URL).

  • API route sees no session
    → Ensure you forward headers in tests (const headersList = await headers()) and the route exports the standard cache killers.