import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { nextCookies } from "better-auth/next-js"; import { sso } from "@better-auth/sso"; import { db } from "~/server/db"; import * as schema from "~/server/db/schema"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: { user: schema.users, session: schema.sessions, account: schema.accounts, verification: schema.verificationTokens, }, }), trustedOrigins: [ "https://beenvoice.soconnor.dev", "https://auth.soconnor.dev", // Authentik IdP for OIDC discovery ], accountLinking: { enabled: true, trustedProviders: ["authentik"], }, emailAndPassword: { enabled: true, password: { hash: async (password) => { const bcrypt = await import("bcryptjs"); return bcrypt.hash(password, 12); }, verify: async ({ hash, password }) => { const bcrypt = await import("bcryptjs"); return bcrypt.compare(password, hash); }, }, }, plugins: [ nextCookies(), sso({ // Only configure default SSO if Authentik credentials are provided defaultSSO: process.env.AUTHENTIK_ISSUER && process.env.AUTHENTIK_CLIENT_ID && process.env.AUTHENTIK_CLIENT_SECRET ? [ { providerId: "authentik", domain: "beenvoice.soconnor.dev", oidcConfig: { issuer: process.env.AUTHENTIK_ISSUER, clientId: process.env.AUTHENTIK_CLIENT_ID, clientSecret: process.env.AUTHENTIK_CLIENT_SECRET, discoveryEndpoint: `${process.env.AUTHENTIK_ISSUER}/.well-known/openid-configuration`, // Explicit endpoints to bypass discovery issues authorizationEndpoint: "https://auth.soconnor.dev/application/o/authorize/", tokenEndpoint: "https://auth.soconnor.dev/application/o/token/", userInfoEndpoint: "https://auth.soconnor.dev/application/o/userinfo/", jwksEndpoint: "https://auth.soconnor.dev/application/o/beenvoice/jwks/", scopes: ["openid", "email", "profile"], pkce: true, }, }, ] : [], }), ], });