This library is in early development. Expect breaking changes.
Guides

Production Deployment

Checklist and best practices for deploying Nuxt Better Auth in production.

Use this guide when your auth flow works locally and you are preparing to ship it to a real environment.

Environment Variables

Production requires these environment variables:

.env.production
# Required: 32+ character secret for session encryption
NUXT_BETTER_AUTH_SECRET="your-32-character-secret-here-minimum"

# Optional: Auto-detected on Vercel/Cloudflare/Netlify
NUXT_PUBLIC_SITE_URL="https://your-app.com"

# OAuth provider credentials (if using)
GOOGLE_CLIENT_ID="..."
GOOGLE_CLIENT_SECRET="..."

Generate a Secure Secret

node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

The secret must be at least 32 characters. Shorter secrets will cause the module to throw an error.

Security Checklist

Before Deploying

  • NUXT_BETTER_AUTH_SECRET is set and 32+ characters
  • NUXT_PUBLIC_SITE_URL set (or using Vercel/Cloudflare/Netlify auto-detection)
  • trustedOrigins includes every active frontend origin (primary domain and preview domain, if used)
  • OAuth redirect URIs configured for production domain
  • NODE_ENV=production is set (disables devtools)

Route Protection

Route rules and definePageMeta are for UX (redirects). Always protect API endpoints with requireUserSession:

server/api/protected.get.ts
export default defineEventHandler(async (event) => {
  const { user } = await requireUserSession(event)
  return { data: 'protected' }
})

Rate Limiting

The module does not include built-in rate limiting. Implement rate limiting at the infrastructure level or use a middleware:

server/middleware/rate-limit.ts
import { getRequestIP } from 'h3'

const requests = new Map<string, number[]>()
const WINDOW_MS = 60_000 // 1 minute
const MAX_REQUESTS = 100

export default defineEventHandler((event) => {
  if (!event.path.startsWith('/api/auth'))
    return

  const ip = getRequestIP(event) || 'unknown'
  const now = Date.now()
  const windowStart = now - WINDOW_MS

  const timestamps = (requests.get(ip) || []).filter(t => t > windowStart)
  timestamps.push(now)
  requests.set(ip, timestamps)

  if (timestamps.length > MAX_REQUESTS) {
    throw createError({ statusCode: 429, message: 'Too many requests' })
  }
})

For production, consider using Cloudflare rate limiting or a Redis-backed solution.

Trusted Origins for Preview Environments

If your workflow uses preview URLs (for example, *.workers.dev), include those origins in your Better Auth server config.

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

export default defineServerAuth({
  trustedOrigins: [
    'https://your-app.com',
    'https://your-preview.workers.dev',
  ],
})

Without the preview origin, browser auth flows can fail because Better Auth rejects cookie-based requests from unknown origins.

NuxtHub Deployment

When deploying with NuxtHub:

  1. Database migrations run automatically during build
  2. Set environment variables in your deployment platform
  3. Ensure @nuxthub/core is listed before @onmax/nuxt-better-auth in modules
nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxthub/core',  // Must be first
    '@onmax/nuxt-better-auth',
  ],
})

Common Issues

"NUXT_BETTER_AUTH_SECRET must be at least 32 characters"

Your secret is too short. Generate a new one using the command above. BETTER_AUTH_SECRET is still accepted as a fallback, but NUXT_BETTER_AUTH_SECRET is the recommended variable.

"siteUrl required in production"

The module auto-detects URLs on Vercel, Cloudflare Pages, and Netlify. For other platforms, set NUXT_PUBLIC_SITE_URL to your production domain.

OAuth Redirects Fail

Ensure your OAuth provider's authorized redirect URIs include:

  • https://your-app.com/api/auth/callback/google
  • https://your-app.com/api/auth/callback/github
  • (Replace with your domain and providers)

DevTools

DevTools are automatically disabled in production (NODE_ENV=production). The /api/_better-auth/* endpoints and /__better-auth-devtools page are not registered.