Authentication
Nenyax uses Better Auth for authentication, with a clear separation between auth data and business data.Architecture
Two User Tables
This separation is intentional. The
users table is an auth-agnostic abstraction layer. If the auth provider changes, only the sync logic updates — all business data stays intact.
Auto-Sync Flow
- User signs up → Better Auth creates a row in
"user"table - User makes first API request → backend receives Bearer token
verify_session_token()validates the token against Better Auth’s"session"table- If no matching
usersrow exists, it reads from"user"and auto-creates one - Same pattern for organizations:
_auto_create_org_from_ba()syncs Better Auth orgs toorganizations
Authentication Methods
Browser → Backend (Session Token)
Dashboard API calls include a Bearer token from the Better Auth session:"session" table (single indexed query).
Agent → Backend (X-User-Id)
The agent worker uses a trusted server-to-server header:Organization Context
Every API request resolves an organization via (in priority order):x-org-idheader — explicit org selection from the frontendactiveOrganizationIdfrom the Better Auth session- User’s first org membership (fallback for single-org users)
organizations table, it is auto-created.
Frontend Auth Setup
Better Auth is configured infrontend/src/lib/auth.ts with:
- Email/password authentication
- Organization plugin (multi-tenancy)
nextCookiesplugin (proper cookie handling for Next.js server components)- Auto-migration of Better Auth tables on startup
Post-Login Navigation
After sign-in, the frontend useswindow.location.href (not router.push) to navigate to the dashboard. This forces a full page load, ensuring auth cookies are properly sent to server components during the initial render.