Stack & Project Structure
Before getting into how Auther authenticates and authorizes, it helps to see the parts list and the floor plan. Auther is a single Next.js application that plays the role of an OAuth2/OIDC identity provider; almost every chapter in Part 1 maps to a specific directory in the layout below, so this page is the map you’ll keep coming back to.
Technology stack
Section titled “Technology stack”Auther leans on a small set of focused libraries rather than a monolithic auth framework. Each layer is swappable in principle, but the combination is what makes the system edge-friendly and type-safe end to end.
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 16 (App Router) | Server-side rendering, API routes, server actions |
| Auth engine | better-auth | Core authentication, session management, the OIDC provider |
| Database | SQLite via Turso / libSQL | Serverless, edge-compatible persistent storage — libSQL is a SQLite fork that speaks HTTP, and Turso hosts it close to the edge so there’s no long-lived DB connection to manage |
| ORM | Drizzle ORM | Type-safe schema definitions and queries |
| Token signing | jose (RS256) | JWT creation and verification — RS256 is asymmetric (sign with a private key, verify with the public one), which is the whole reason clients can verify offline |
| Policy engine | wasmoon (Lua-in-WASM) | ABAC policy evaluation and pipeline scripts — Lua compiled to WebAssembly, so user-authored logic runs in a tight sandbox with no access to the host |
| Queue | Upstash QStash | Asynchronous webhook delivery with retries — an HTTP-based message queue, so workers are just API routes (no always-on worker process) |
| Cache | Upstash Redis | Webhook idempotency and rate limiting — “have I already processed this delivery?” lookups, plus per-client throttling |
| Resend + React Email | Transactional email (verification, password reset) | |
| UI | Radix UI + Tailwind CSS 4 | The admin dashboard |
| Validation | Zod | Schema validation for API inputs and authorization models |
| Editor | CodeMirror 6 | Lua script editing with LSP-like features |
| Visualization | React Flow (@xyflow/react) | The pipeline DAG editor |
| Charts | Recharts | Dashboard metrics visualization |
Most of the table is interchangeable, but two rows are load-bearing — they decide how the rest of the system is shaped:
- RS256 signing via
jose. A token signed with a private key can be verified by anyone holding the matching public key. So clients fetch Auther’s public key once, cache it, and verify every token themselves — Auther is never on the request hot path. Swap to a symmetric scheme (HS256, one shared secret) and every verification becomes a call back to the server. The whole “verify offline” story collapses. - Lua-in-WASM via
wasmoon. Both attribute-based policies and lifecycle pipelines run user-authored logic. Running that as native code would mean a redeploy per change and a sandbox you don’t fully trust. Compiling Lua to WebAssembly gives you a hard sandbox and lets policies change at runtime — no rebuild, no server restart.
Project structure
Section titled “Project structure”The codebase separates the three concerns you’ll spend the most time in:
authentication config (lib/auth.ts), the authorization engine (lib/auth/), and
the database schemas that back them (db/). The split between schema files mirrors
the subsystems exactly — there’s a file for ReBAC, one for ABAC, one for pipelines,
and so on.
Directorysrc/
Directoryapp/
Directoryadmin/ admin dashboard (users, clients, groups, keys…)
- …
Directoryapi/
Directoryauth/
Directory[…betterAuth]/ better-auth catch-all route handler
- …
Directoryapi-key/exchange/ API key → JWT exchange endpoint
- …
Directorycheck-permission/ runtime ABAC permission-check endpoint
- …
Directoryverify-invite/ invite-token verification endpoint
- …
Directoryinternal/
Directoryrotate-jwks/ JWKS rotation cron endpoint
- …
Directoryqueues/ QStash webhook delivery workers
- …
Directorycleanup-traces/ pipeline trace cleanup
- …
Directorywebhooks/payload/ inbound webhook receiver
- …
Directorysign-in/ authentication UI
- …
Directoryreset-password/ password-reset UI
- …
Directorycomponents/
Directoryadmin/ admin dashboard, pipelines, access control
- …
Directoryauth/ authentication form components
- …
Directoryui/ shared UI (code editor, forms)
- …
Directorydb/
- auth-schema.ts better-auth core tables (user, session, account, apikey, jwks, oauth)
- app-schema.ts application tables (access control, webhooks, client metadata, groups)
- rebac-schema.ts ReBAC tables (access_tuples, authorization_models)
- abac-schema.ts ABAC tables (audit logs, policy versions)
- pipeline-schema.ts pipeline tables (scripts, execution plans, graphs, traces, spans)
- platform-access-schema.ts registration contexts, invites, permission requests/rules, templates
- metrics-schema.ts metrics storage table
Directorylib/
Directoryauth/ the authorization engine (permission service, models, policy engine, guards)
- …
- auth.ts better-auth server configuration (the central auth config)
- auth-client.ts better-auth React client for browser-side auth
- session.ts server-side session helpers (
getSession,requireAuth,requireAdmin) Directoryrepositories/ data-access layer (15+ repository classes)
- …
Directoryservices/ business logic (API-key resolver, metrics, registration, templates)
- …
Directorypipelines/ pipeline integration (definitions, hooks, execution)
- …
Directorywebhooks/ webhook delivery (signatures, queue, service)
- …
Directoryemail/ email sending (Resend) and templates (React Email)
- …
Directorymiddleware/ origin validation
- …
Directoryutils/ helpers (CORS, OAuth, URL handling, wildcards)
- …
Directoryschemas/ Zod validation schemas (ReBAC models, clients, users, groups)
- …
- proxy.ts Next.js edge middleware (route protection)
- env.ts environment-variable validation (Zod-based)
Directoryscripts/ CLI utilities (seed admin, seed clients, test auth flow)
- …
Directorydrizzle/ database migrations
- …
Directorydocs/ architecture and implementation documents
- …