ApplicationsStorefront

Auth and store resolution

Customer authentication and host-based tenant resolution in the storefront.

The storefront handles two cross-cutting concerns: customer authentication (Better Auth) and tenant resolution (which merchant store to display).

Customer authentication

Setup

Better Auth is configured in lib/auth/server.ts:

SettingValue
ProviderEmail/password only
DatabaseNeon via Drizzle (lib/auth/db.ts, lib/auth/schema.ts)
Tablesuser, session, account, verification
Organization pluginNot enabled — buyers are not org members

Auth seam

lib/auth/index.ts exposes getSession() and getCurrentUser() as thin Better Auth wrappers for pages and server actions.

Commerce identity

Logged-in buyers map to customers.id (internal UUID) via customers.auth_user_id. Orders and carts never store Better Auth user.id or email. See Privacy & data.

On sign-up, ensure a commerce customer row exists for the tenant (ensureCustomerForAuthUser).

Protected routes

Account pages check for an active session:

ts
const session = await getSession()
if (!session) redirect('/login')

The API resolves the session → customers.id and filters orders server-side.

API routes

Better Auth handler at /api/auth/[...all] handles sign-up, sign-in, sign-out, and session cookies.

Tenant resolution

How it works

lib/tenant.ts → resolveTenantId():

  1. Custom domain lookup (tenant_domain, verified)
  2. Subdomain {slug}.{NEXT_PUBLIC_PLATFORM_DOMAIN} → organization by slug
  3. Otherwise redirect to the marketing site (NEXT_PUBLIC_WEB_URL)

There is no fallback tenant.

Resolution priority

PrioritySourceExample
1Custom domain (verified)shop.example.com
2Platform subdomainmerchant.prood.app
3Unknown hostRedirect to marketing site

Database lookup

lookupTenantByHost() from @prood/platform (re-exported in lib/tenant-db.ts).

Forwarding to API

The storefront API client forwards x-storefront-host and the session cookie to the Commerce API for tenant-scoped routes.

Development setup

  1. Run pnpm db:migrate and pnpm db:seed
  2. With NEXT_PUBLIC_PLATFORM_DOMAIN=localhost, open http://prood-demo.localhost:3000 (the seeded org_demo store, slug prood-demo)