import { betterAuth } from 'better-auth'; import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { 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; 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', 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, }); } export type Auth = ReturnType;