import { betterAuth } from 'better-auth' import { admin } from 'better-auth/plugins' import { actor, fabric } from '@pikku/better-auth' import { pikkuBetterAuth } from '#pikku/pikku-types.gen.js' export const auth = pikkuBetterAuth(async ({ kysely, secrets, variables }) => { const BETTER_AUTH_SECRET = await secrets.getSecret('BETTER_AUTH_SECRET') // Genuinely optional: unset simply disables /api/auth/sign-in/actor (scenarios // off for this deployment) — the actor plugin refuses all sign-ins // without it. const SCENARIO_ACTOR_SECRET = await secrets .getSecret('SCENARIO_ACTOR_SECRET') .catch(() => undefined) // Fabric operator admin: the RSA public key the control plane's token is // verified against. The Fabric deployer pushes FABRIC_AUTH_PUBLIC_KEY onto // every stage; locally it's simply absent, which disables /sign-in/fabric. // Asymmetric — the app verifies, it can never forge an operator login. const FABRIC_AUTH_PUBLIC_KEY = await variables.get('FABRIC_AUTH_PUBLIC_KEY') return betterAuth({ secret: BETTER_AUTH_SECRET, database: { db: kysely as any, type: 'sqlite' }, emailAndPassword: { enabled: true }, session: { cookieCache: { enabled: true, maxAge: 5 * 60 }, }, advanced: { database: { generateId: 'uuid' } }, user: { additionalFields: { role: { type: 'string', required: false, defaultValue: 'client', input: false, }, locale: { type: 'string', required: false, defaultValue: 'de', input: true, }, }, }, // Scenario actors: synthetic users (user.actor = true, see // db/sqlite/0012-user-actor.sql) signed in by pikkuScenario via // POST /api/auth/sign-in/actor { email, secret }. Never signs in real users. // // admin(): exposes /api/auth/admin/* (listUsers, setRole, impersonateUser, // …) so an app admin can list and "view as" their end-users — this is what // the Fabric console's Users tab drives. Adds role/banned/impersonatedBy // columns (see db/sqlite/0013-admin.sql). No user is an admin by default: // grant it by setting a user's `role` to 'admin' (or pass // `adminUserIds: [...]` here) — the admin API refuses non-admins. // // fabric(): exposes /api/auth/sign-in/fabric — the Fabric control plane // mints a short-lived RS256 token and signs in as a synthetic `fabric: true` // admin operator (db/sqlite/0014-fabric.sql), so the console Users tab can // list/impersonate real users without the operator being one of them. It // pairs with admin() and verifies against FABRIC_AUTH_PUBLIC_KEY; missing // key disables the endpoint. plugins: [ actor({ secret: SCENARIO_ACTOR_SECRET }), admin(), fabric({ publicKey: FABRIC_AUTH_PUBLIC_KEY }), ], }) })