nuxt-better-auth-utils
v0.1.12
Published
Nuxt module for Better Auth — full lifecycle integration with auto-wired handler, SSR, session state, and typed server/client APIs
Readme
nuxt-better-auth-utils
Nuxt module for Better Auth — full lifecycle integration with auto-wired handler, SSR, session state, and typed server/client APIs.
Features
- Auto-registered API handler (
/api/auth/**) - SSR session pre-fetch — session available on first render
useAuth()composable with reactivesession,user,loggedIn, and rawclientaccessuseServerAuth()server utility withrequireSession,getSession, and rawauthinstanceauthroute middleware for protecting pagescustomSessionClient<AuthInstance>()auto-injected for full session type inference- Session signal listener for cross-tab sync
- Zero opinions on database adapter, plugins, or auth strategy
Setup
npx nuxi module add nuxt-better-auth-utilsAdd to nuxt.config.ts:
export default defineNuxtConfig({
modules: ['nuxt-better-auth-utils'],
})Set BETTER_AUTH_SECRET in your .env (or NUXT_SECRET).
Configuration
Server Config — auth.server.config.ts
Standard Better Auth options. The module auto-injects secret.
import { defineAuthConfig } from '#better-auth-utils'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { organization } from 'better-auth/plugins'
export default defineAuthConfig({
database: drizzleAdapter(db, { provider: 'pg' }),
emailAndPassword: { enabled: true },
plugins: [organization()],
})Supports factory functions for deferred access to runtime utilities:
export default defineAuthConfig(() => {
const db = useDrizzle()
return {
database: drizzleAdapter(db, { provider: 'pg' }),
}
})Client Config — auth.client.config.ts
import { defineAuthClientConfig } from '#better-auth-utils'
import { organizationClient } from 'better-auth/client/plugins'
export default defineAuthClientConfig({
plugins: [organizationClient()],
})Both files are optional. If absent, the module uses bare defaults.
Module Options
// nuxt.config.ts
export default defineNuxtConfig({
betterAuthUtils: {
configPath: '~~/', // where to find config files
redirectTo: '/auth/sign-in', // auth middleware redirect
handlerRoute: '/api/auth/**', // API handler route
},
})Usage
Client — useAuth()
Auto-imported composable with reactive session state and raw client access.
const { session, user, loggedIn, signOut, fetch, client } = useAuth()
// Use the raw Better Auth client for any operation
await client.signIn.email({ email, password })
await client.signUp.email({ email, password, name })
await client.organization.create({ name: 'Acme' })
// Convenience helpers
await signOut({ redirectTo: '/login' })
await fetch() // refresh sessionServer — useServerAuth()
Auto-imported in server routes.
// server/api/me.ts
export default defineEventHandler(async (event) => {
const { requireSession } = useServerAuth()
const session = await requireSession(event) // throws 401 if unauthenticated
return session.user
})// Advanced: use raw Better Auth instance
export default defineEventHandler(async (event) => {
const { auth } = useServerAuth()
const users = await auth.api.listUsers()
})Protecting Pages
definePageMeta({
middleware: 'auth',
})Custom Session
Use Better Auth's customSession plugin with the satisfies pattern for full type inference:
import { defineAuthConfig } from '#better-auth-utils'
import type { BetterAuthOptions } from 'better-auth'
import { customSession, organization } from 'better-auth/plugins'
export default defineAuthConfig(() => {
const baseOptions = {
database: myAdapter(),
plugins: [organization()],
} satisfies BetterAuthOptions
return {
...baseOptions,
plugins: [
...baseOptions.plugins,
customSession(async ({ user, session }) => {
// session.activeOrganizationId is typed correctly
return { user, session: { ...session, extra: 'data' } }
}, baseOptions),
],
}
})The module auto-injects customSessionClient<AuthInstance>() on the client, so useAuth().session is fully typed with your custom session fields.
License
MIT
