Guides
External Auth Backend
Use nuxt-better-auth with a separate Better Auth server.
Use this guide when the Nuxt app is only the frontend and Better Auth runs somewhere else.
When your Better Auth server runs on a separate backend (e.g., standalone h3/Nitro project, Express, or any other server), use clientOnly mode.
When to Use
- Microservices architecture: Auth service is a separate deployment
- Shared auth: Multiple frontends share one auth backend
- Existing backend: You already have a Better Auth server running elsewhere
Configuration
1. Enable Client-Only Mode
nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/better-auth'],
auth: {
clientOnly: true,
},
})
2. Point the Client to the External Server
Set the site URL to your external auth server:
.env
NUXT_PUBLIC_SITE_URL="https://auth.example.com"
This value becomes the default Better Auth client base URL in client-only mode. You can instead set baseURL in the client config. An explicit client config value takes precedence over the site URL:
app/auth.config.ts
import { defineClientAuth } from '@nuxtjs/better-auth/config'
export default defineClientAuth({
baseURL: 'https://auth.example.com',
})
3. Configure Route Redirect Targets (Optional)
Control redirect paths directly in route auth rules:
nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/app/**': { auth: { only: 'user', redirectTo: '/login' } },
'/login': { auth: { only: 'guest', redirectTo: '/app' } },
},
})
What Changes in Client-Only Mode
| Feature | Full Mode | Client-Only |
|---|---|---|
server/auth.config.ts | Required | Not needed |
/api/auth/** handlers | Auto-registered | Skipped |
| Auth secret configuration | Required | Not needed |
| Server middleware | Enabled | Skipped |
| Schema generation | Enabled | Skipped |
| Devtools | Enabled | Skipped |
| SSR session hydration | Server-side | Client-side only |
useUserSession() | Works | Works |
| Route protection | Works | Works (client-side) |
<BetterAuthState> | Works | Works |
Important Notes
In client-only mode, all auth requests go directly to your external server. Ensure:
- CORS is configured on your auth server to allow requests from your frontend (with
credentials: true) - Cookies use
SameSite=None; Securefor cross-origin requests (HTTPS required) - Your auth server's
trustedOriginsincludes your frontend URL
In client-only mode,
NUXT_PUBLIC_SITE_URL is used as the auth client base URL unless defineClientAuth provides an explicit baseURL.
Use routeRules.auth.redirectTo (or page meta auth.redirectTo) to control frontend navigation paths.Server utilities like
serverAuth(), getUserSession() and requireUserSession() are not available in client-only mode since there's no local auth server.SSR Considerations
In client-only mode, session data is fetched client-side only. This means:
- Server-rendered pages won't have access to session data during SSR
- Pages will initially render as "unauthenticated" and hydrate with session data on the client
- Use
<BetterAuthState>component to handle loading states gracefully
<template>
<BetterAuthState>
<template #default="{ user }">
<div v-if="user">Welcome, {{ user.name }}</div>
<div v-else>Please log in</div>
</template>
<template #placeholder>
<div>Loading...</div>
</template>
</BetterAuthState>
</template>
If you need SSR session hydration, consider using full mode with a local auth server instead.
Example Architecture
┌─────────────────┐ ┌─────────────────┐
│ Nuxt App │────▶│ Auth Server │
│ (clientOnly) │ │ (Better Auth) │
│ │◀────│ │
└─────────────────┘ └────────┬────────┘
│
┌────────▼────────┐
│ Database │
└─────────────────┘
Related
- Configuration - Module options reference
- Database-Less Mode - JWE sessions without database