Auth Setup Guide
This guide describes how to add and configure authentication for the Operyn dashboard. It assumes you are following the plan: better-auth in the Next.js dashboard, with SSO (Google, GitHub), organization plugin, and optional RBAC, in a modular way that can later be moved to a dedicated auth service.
Prerequisites
- Existing Operyn monorepo with dashboard and Postgres (same DB used by services).
- Environment variables for Postgres (e.g.
DATABASE_URLorPOSTGRES_*) available to the dashboard app.
Concepts
- Authentication — Where auth lives, SSO, session, and backend user context.
- Roles and permissions — Personas, permission list, and role–permission matrix.
Implementation Order (high level)
- Dependencies and database — Add
better-auth,@better-auth/drizzle-adapter, and plugin packages. Add a Drizzle client for the dashboard (e.g.lib/auth/db.ts) using the same Postgres. Runnpx auth@latest generateand apply migrations (optionally in a dedicatedauthschema). - Auth config and API route — Implement the central auth config (Drizzle adapter, Google, GitHub, email/password, organization plugin, optional RBAC). Add the auth client config. Add
app/api/auth/[...all]/route.tsthat delegates to the better-auth handler. - Auth feature and routes — Add sign-in and sign-up pages under a marketing or auth route group. Add a session provider and, if using the organization plugin, an org switcher. Protect
/consolevia middleware (redirect unauthenticated users to/login). - Organization and RBAC usage — Create a default organization on first login if needed. Add organization (and team) management under Settings. Implement permission checks (e.g. a small
can(session, 'remediation:approve')helper) using the role–permission matrix. - Backend JWT (optional) — Define JWT payload in
@operyn/shared-types. Have the dashboard send a JWT when calling Incident Engine and Remediation Engine. Add a JWT guard in each NestJS service to validate the token and attach user context.
Environment Variables (dashboard)
Typical variables for auth:
| Variable | Description |
|---|---|
DATABASE_URL | Postgres connection string (or build from POSTGRES_HOST, POSTGRES_USER, etc.). |
BETTER_AUTH_SECRET | Secret for signing sessions; use a long random string in production. |
BETTER_AUTH_URL | Base URL of the dashboard (e.g. http://localhost:3000 for dev). |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | For Google sign-in (optional). |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET | For GitHub sign-in (optional). |
For local bun dev with Docker Compose, the minimum you need is:
- Postgres connectivity for the dashboard (
DATABASE_URLorPOSTGRES_HOST+ credentials from root.env) BETTER_AUTH_SECRETBETTER_AUTH_URLBETTER_AUTH_TRUSTED_ORIGINS(so Better Auth can verify callback/origin safely)
For enterprise SSO (OIDC/SAML), additional variables are required; see better-auth SSO plugin documentation.
File Layout (dashboard)
lib/auth/config.ts— SinglebetterAuth({ ... })instance (database, providers, organization, RBAC).lib/auth/db.ts— Drizzle client for auth tables.lib/auth/client.ts—createAuthClient(...)for the browser.app/api/auth/[...all]/route.ts— Thin handler delegating to better-auth.features/auth/components/— Sign-in, sign-up, session provider, org switcher.middleware.ts— Protect/console, allow/,/login,/sign-up,/api/auth/*.
After Setup
- Configure at least one sign-in method (email/password or a social provider).
- Create or join an organization so users have an org context.
- Use the roles and permissions matrix to gate UI and, if needed, backend endpoints.