This library is in early development. Expect breaking changes.
Getting Started

Configuration

Configure the module options and your Better Auth server instance.
Prompt
Configure @onmax/nuxt-better-auth module options and server auth.

- In `nuxt.config.ts`, set `auth.redirects` (login, guest, authenticated, logout) and `auth.preserveRedirect`
- Use `routeRules` or `nitro.routeRules` to define per-route auth: `{ auth: { only: 'user', redirectTo: '/login' } }`
- In `server/auth.config.ts`, use `defineServerAuth` (object or function syntax) to configure plugins and providers
- The function syntax receives `ctx` with `runtimeConfig` and `db` (NuxtHub)
- The module auto-injects `secret` and `baseURL` — do not set them in defineServerAuth
- Base URL priority: runtimeConfig > request URL > platform env vars > localhost
- Set `NUXT_PUBLIC_SITE_URL` for custom domains or deterministic OAuth callbacks

Read more: https://better-auth.nuxt.dev/raw/getting-started/configuration.md
Source: https://github.com/nuxt-modules/better-auth

Module Configuration

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@onmax/nuxt-better-auth'],
  auth: {
    redirects: {
      login: '/login',
      guest: '/',
      // authenticated: '/app', // optional
      // logout: '/goodbye', // optional
    },
    preserveRedirect: true,
    redirectQueryKey: 'redirect',
  },
  routeRules: {
    '/app/**': { auth: { only: 'user', redirectTo: '/login' } },
    '/login': { auth: { only: 'guest', redirectTo: '/app' } },
  },
})
You can define auth route rules in either routeRules or nitro.routeRules. The module supports both. If both are set, it uses nitro.routeRules.
clientOnly
boolean
Default: falseEnable client-only mode for external auth backends. When true:
  • Skips server/auth.config.ts requirement
  • Skips server-side setup (API handlers, middleware, schema generation, devtools)
  • Skips secret validation
Use this when your Better Auth server runs on a separate backend (e.g., standalone h3/Nitro project).See External Auth Backend guide.
serverConfig
string
Default: 'server/auth.config'Path to the server auth config file, relative to the project root.
clientConfig
string
Default: 'app/auth.config'Path to the client auth config file, relative to the project root.
redirects
{ login?: string, guest?: string, authenticated?: string, logout?: string }
Default: { login: '/login', guest: '/' }Global redirect fallbacks:
  • login: where to redirect unauthenticated users
  • guest: where to redirect authenticated users trying to access guest-only routes
  • authenticated: where to navigate after successful authenticated signIn / signUp when no onSuccess callback is provided
  • logout: where to navigate after logout (no default)
Per-route redirectTo takes precedence when set.
preserveRedirect
boolean
Default: trueWhen redirecting unauthenticated users to a login route, append the original requested path as a query param.Configure redirect targets per-route with routeRules.auth.redirectTo or definePageMeta({ auth: { redirectTo } }).
redirectQueryKey
string
Default: 'redirect'Query param key used when preserveRedirect is enabled.
hubSecondaryStorage
boolean | 'custom'
Default: falseEnable secondary storage for sessions, reducing database hits for session validation.
  • true — Use NuxtHub KV. Requires NuxtHub Integration with hub: { kv: true }. Build fails if KV is not enabled. Generated schema remains stable and keeps core auth tables (user, account, session, verification).
  • 'custom' — You provide your own secondaryStorage in defineServerAuth() (required; the build fails in production if missing). The module won't inject NuxtHub KV, and this mode can omit the session table from generated schema.
  • false (default) — No secondary storage from the module. User-provided secondaryStorage in defineServerAuth() is not overridden.
schema.usePlural
boolean
Default: falsePluralize table names (user → users)
schema.casing
'camelCase' | 'snake_case'
Default: camelCaseColumn/table name casing. Falls back to hub.db.casing when not specified.

Redirect Targets (RouteRules-First)

Prefer redirect paths on route-level auth config:

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/app/**': { auth: { only: 'user', redirectTo: '/login' } },
    '/login': { auth: { only: 'guest', redirectTo: '/app' } },
  },
})

You can use the same auth route rules under nitro.routeRules:

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    routeRules: {
      '/app/**': { auth: { only: 'user', redirectTo: '/login' } },
      '/login': { auth: { only: 'guest', redirectTo: '/app' } },
    },
  },
})

If redirectTo is omitted, shorthand fallbacks apply:

  • auth: 'user' falls back to /login
  • auth: 'guest' falls back to /

If you want global defaults for those fallbacks, use auth.redirects.

Default post-auth navigation:

  • auth.redirects.authenticated is used when signIn / signUp complete with an authenticated session and no explicit onSuccess.
  • If a preserved redirect query param is present and safe (?redirect=), it takes precedence over auth.redirects.authenticated.

Server Configuration

Define your authentication logic in server/auth.config.ts, including plugins, providers, and settings.

defineServerAuth

Use the defineServerAuth helper to ensure type safety and access context. It accepts an object or function syntax.

server/auth.config.ts
import { defineServerAuth } from '@onmax/nuxt-better-auth/config'

// Object syntax (simplest)
export default defineServerAuth({
  emailAndPassword: { enabled: true }
})

// Function syntax (access context)
export default defineServerAuth((ctx) => ({
  emailAndPassword: { enabled: true }
}))
The module automatically injects secret and baseURL. You don't need to configure these in defineServerAuth.
  • Secret: Priority: nuxt.config.ts runtimeConfig > NUXT_BETTER_AUTH_SECRET > BETTER_AUTH_SECRET
  • Base URL: The module auto-detects the base URL on Vercel/Cloudflare/Netlify. For other platforms, set NUXT_PUBLIC_SITE_URL

Context Options

When using the function syntax, defineServerAuth callback receives a context object with useful properties:

server/auth.config.ts
import { defineServerAuth } from '@onmax/nuxt-better-auth/config'

export default defineServerAuth((ctx) => ({
  emailAndPassword: { enabled: true },

  appName: ctx.runtimeConfig.public.siteUrl ? 'Better Auth App' : 'Better Auth',
}))
  • ctx.runtimeConfig: Nuxt runtime config.
  • ctx.db: NuxtHub database connection when NuxtHub DB is enabled. Do not set database when using module-managed adapters.
  • ctx.requestOrigin: Current request origin when auth is created with serverAuth(event).

Use requestOrigin when Better Auth config needs the current request host, such as trusted origins:

server/auth.config.ts
import { defineServerAuth } from '@onmax/nuxt-better-auth/config'

export default defineServerAuth(({ requestOrigin }) => ({
  trustedOrigins: requestOrigin ? [requestOrigin] : [],
}))
For configured canonical URLs, read runtimeConfig.public.siteUrl. requestOrigin is optional and only available when auth is created from a request event. If allowed origins vary while using an explicit siteUrl, configure those origins explicitly or use Better Auth's trustedOrigins function form, because the auth instance can be cached.

Session Enrichment

You can enrich session payloads with Better Auth's custom-session plugin through plugins in defineServerAuth. This module does not provide a separate requestSession.enrich option.

See the full recipe in Server Utilities.

Base URL Configuration

The module resolves siteUrl using this priority:

PrioritySourceWhen Used
1runtimeConfig.public.siteUrlExplicit config (always wins)
2Request URLAuto-detected from the current Nitro request (event)
3VERCEL_URL, CF_PAGES_URL, URLPlatform env vars (Vercel, Cloudflare, Netlify)
4http://localhost:3000Development only

In server handlers, pass event to serverAuth(event) so request URL detection can run. In non-request contexts (seed scripts, tasks, startup plugins), the module uses environment/platform fallbacks.

Set an explicit site URL in nuxt.config.ts for deterministic OAuth callbacks and origin checks:

nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      siteUrl: process.env.NUXT_PUBLIC_SITE_URL || 'http://localhost:3000',
    },
  },
})

Use NUXT_PUBLIC_SITE_URL to provide this value per environment.

Custom domains or self-hosted: You should set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) when using custom domains or deploying to your own VPS/server. Platform env vars return auto-generated URLs, not your custom domain.

.env
NUXT_PUBLIC_SITE_URL="https://your-domain.com"
The module can auto-detect the request URL on most deployments. You should still set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) when callback consistency matters, such as local OAuth debugging, custom domains, or non-request contexts like seed scripts.

Runtime Config

Configure secrets using environment variables (see Installation).

.env
NUXT_BETTER_AUTH_SECRET="your-super-secret-key"
NUXT_PUBLIC_SITE_URL="https://your-domain.com" # Optional on Vercel/Cloudflare/Netlify
Use NUXT_BETTER_AUTH_SECRET as the primary secret variable. BETTER_AUTH_SECRET remains supported as a fallback for existing setups.

For Module Authors

Other Nuxt modules can extend the authentication configuration:

// In your Nuxt module
export default defineNuxtModule({
  setup(options, nuxt) {
    nuxt.hook('better-auth:config:extend', (config) => {
      config.plugins = [...(config.plugins || []), myPlugin()]
    })
  }
})

Access sessions from server handlers:

const { user, session } = await getUserSession(event)
if (!user) throw createError({ statusCode: 401 })