import { betterAuth } from 'better-auth'; import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { admin, genericOAuth } from 'better-auth/plugins'; import type { Db } from '@mosaic/db'; export interface AuthConfig { db: Db; baseURL?: string; secret?: string; } export function createAuth(config: AuthConfig) { const { db, baseURL, secret } = config; const authentikIssuer = process.env['AUTHENTIK_ISSUER']; const authentikClientId = process.env['AUTHENTIK_CLIENT_ID']; const authentikClientSecret = process.env['AUTHENTIK_CLIENT_SECRET']; const plugins = authentikClientId ? [ genericOAuth({ config: [ { providerId: 'authentik', clientId: authentikClientId, clientSecret: authentikClientSecret ?? '', discoveryUrl: authentikIssuer ? `${authentikIssuer}/.well-known/openid-configuration` : undefined, authorizationUrl: authentikIssuer ? `${authentikIssuer}/application/o/authorize/` : undefined, tokenUrl: authentikIssuer ? `${authentikIssuer}/application/o/token/` : undefined, userInfoUrl: authentikIssuer ? `${authentikIssuer}/application/o/userinfo/` : undefined, scopes: ['openid', 'email', 'profile'], }, ], }), ] : undefined; const corsOrigin = process.env['GATEWAY_CORS_ORIGIN'] ?? 'http://localhost:3000'; const trustedOrigins = corsOrigin.split(',').map((o) => o.trim()); return betterAuth({ database: drizzleAdapter(db, { provider: 'pg', usePlural: true, }), baseURL: baseURL ?? process.env['BETTER_AUTH_URL'] ?? 'http://localhost:4000', secret: secret ?? process.env['BETTER_AUTH_SECRET'], basePath: '/api/auth', trustedOrigins, emailAndPassword: { enabled: true, }, user: { additionalFields: { role: { type: 'string', required: false, defaultValue: 'member', input: false, }, }, }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, // refresh daily }, plugins: [...(plugins ?? []), admin({ defaultRole: 'member', adminRoles: ['admin'] })], }); } export type Auth = ReturnType;