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 },

  // Access the database connection via ctx.db when using NuxtHub
  // Example: pass ctx.db to your own plugin/helper.
  // Do not set `database` here when using module-managed adapters.
  appName: ctx.runtimeConfig.public.siteUrl ? 'Better Auth App' : 'Better Auth',

  // Access runtime config if needed
  // someValue: ctx.runtimeConfig.customKey
}))

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 })