nuxt-x-auth-better
Nuxt 4 authentication layer powered by Better Auth — 7 XAuth-prefixed components, a useXAuth composable, global auth middleware, 6 pre-built pages, and a fully typed app.config.ts interface built on Nuxt UI v4.
nuxt-x-auth-better
Better Auth frontend layer for Nuxt 4. Provides 7 auto-imported XAuth-prefixed components, a useXAuth composable, a global auth middleware, 7 pre-built auth pages, and a fully typed app.config.ts interface — all built on Nuxt UI v4. Pairs with @xenterprises/fastify-x-auth-better on the backend.
Installation
npm install @xenterprises/nuxt-x-auth-better
// nuxt.config.ts
export default defineNuxtConfig({
extends: [['@xenterprises/nuxt-x-auth-better', { install: true }]],
runtimeConfig: {
public: {
x: {
auth: {
baseUrl: process.env.NUXT_PUBLIC_AUTH_BASE_URL || '',
authPath: '/auth',
},
},
},
},
})
Override defaults in app.config.ts:
export default defineAppConfig({
xAuth: {
redirects: {
login: '/auth/login',
signup: '/auth/signup',
afterLogin: '/',
afterSignup: '/',
afterLogout: '/auth/login',
forgotPassword: '/auth/forgot-password',
},
features: {
oauth: false,
magicLink: false,
otp: false,
forgotPassword: true,
signup: true,
},
oauthProviders: [],
ui: {
showLogo: true,
showBrandName: true,
brandName: '',
tagline: '',
layout: 'centered',
},
},
})
What the Layer Provides
Components (auto-imported, XAuth prefix):
XAuthLogin— Email/password login form with optional magic link and OAuthXAuthSignup— Registration form with name, email, and passwordXAuthForgotPassword— Password reset request formXAuthMagicLink— Magic link email input formXAuthOAuthButton— Single OAuth provider button (Google, GitHub, etc.)XAuthOAuthButtonGroup— Multiple OAuth provider buttons fromapp.config.tsXAuthHandler— Callback handler for OAuth and magic link redirects
Composable:
useXAuth()— Full Better Auth client wrapper with session state, auth methods, and user management
Pages:
/auth/login— Login page/auth/signup— Signup page/auth/forgot-password— Forgot password page/auth/magic-link— Magic link request page/auth/reset-password— Reset password page (token from email link)/auth/handler/[...slug]— OAuth callback and magic link verification handler/auth/logout— Logout action page
Middleware:
auth.global— Global route guard; redirects unauthenticated users to login and authenticated users away from guest-only routes
App Config Options
Configure under the xAuth key in app.config.ts:
| Option | Type | Default | Description |
|---|---|---|---|
redirects.login | string | '/auth/login' | Login page path |
redirects.signup | string | '/auth/signup' | Signup page path |
redirects.afterLogin | string | '/' | Redirect after successful login |
redirects.afterSignup | string | '/' | Redirect after successful signup |
redirects.afterLogout | string | '/auth/login' | Redirect after logout |
redirects.forgotPassword | string | '/auth/forgot-password' | Forgot password page path |
features.oauth | boolean | false | Show OAuth provider buttons |
features.magicLink | boolean | false | Show magic link option |
features.otp | boolean | false | Show OTP input |
features.forgotPassword | boolean | true | Show forgot password link |
features.signup | boolean | true | Show signup link |
oauthProviders | array | [] | OAuth providers: { id, label, icon } |
ui.showLogo | boolean | true | Show logo on auth pages |
ui.showBrandName | boolean | true | Show brand name on auth pages |
ui.brandName | string | '' | Brand name text |
ui.tagline | string | '' | Tagline below brand name |
ui.layout | 'centered' | 'split' | 'centered' | Auth page layout |
ui.background.enabled | boolean | true | Show background on auth pages |
ui.background.imageUrl | string | '' | Background image URL |
ui.background.overlayOpacity | number | 55 | Overlay opacity (0–100) |
ui.background.blur | boolean | true | Blur background image |
ui.card.glass | boolean | false | Glass morphism card effect |
ui.split.heroPosition | 'left' | 'right' | 'left' | Hero panel position in split layout |
ui.split.headline | string | '' | Headline in split layout hero |
ui.split.features | string | [] | Feature list in split layout hero |
ui.legal.copyright | string | '' | Copyright text in footer |
ui.legal.links | array | [] | Footer links: { label, to } |
Runtime Config
| Key | Env Variable | Default | Description |
|---|---|---|---|
public.x.auth.baseUrl | NUXT_PUBLIC_AUTH_BASE_URL | '' | Base URL of the Fastify API server |
public.x.auth.authPath | — | '/auth' | Better Auth mount path on the API server |
The full auth URL is constructed as baseUrl + authPath (e.g. https://api.example.com/auth).
useXAuth() Composable
const {
user, // ComputedRef<AuthUser | null>
isAuthenticated, // ComputedRef<boolean>
isLoading, // ComputedRef<boolean>
emailSent, // Ref<boolean>
session, // ComputedRef<Session | null>
sessionError, // ComputedRef<Error | null>
config, // ComputedRef<AuthConfig>
authClient, // Better Auth client instance
login, // (email, password) => Promise<AuthUser | null>
signup, // (email, password, name?) => Promise<AuthUser | null>
logout, // () => Promise<boolean>
forgotPassword, // (email) => Promise<boolean>
resetPassword, // (token, newPassword) => Promise<true | { error }>
loginWithProvider, // (providerName) => Promise<boolean>
sendMagicLink, // (email, options?) => Promise<boolean>
getCurrentUser, // () => Promise<AuthUser | null>
getToken, // () => Promise<string | null>
getAuthHeaders, // () => Promise<{ Authorization: string }>
handleMagicLinkCallback, // (token) => Promise<true | { error }>
changePassword, // (currentPassword, newPassword) => Promise<true | { error }>
updateUser, // ({ name?, image? }) => Promise<true | { error }>
deleteAccount, // () => Promise<boolean>
resetState, // () => void
} = useXAuth()
Minimal Usage Example
<script setup>
const { user, isAuthenticated, logout } = useXAuth()
</script>
<template>
<div v-if="isAuthenticated">
Welcome, {{ user?.name }}
<UButton @click="logout">Sign Out</UButton>
</div>
<XAuthLogin v-else />
</template>
OAuth Providers Example
// app.config.ts
export default defineAppConfig({
xAuth: {
features: { oauth: true },
oauthProviders: [
{ id: 'google', label: 'Google', icon: 'i-simple-icons-google' },
{ id: 'github', label: 'GitHub', icon: 'i-simple-icons-github' },
],
},
})
<XAuthOAuthButtonGroup />
Global Middleware Behavior
The auth.global middleware runs on every route navigation:
| Route type | Authenticated | Unauthenticated |
|---|---|---|
Guest-only (/auth/login, /auth/signup, etc.) | Redirect to afterLogin | Allow |
Public (/auth/handler/*, /auth/logout) | Allow | Allow |
| All other routes | Allow | Redirect to login |
Layer Architecture
| Path | Purpose |
|---|---|
nuxt.config.ts | Registers @nuxt/ui, injects runtime config schema |
app.config.ts | All configurable options under xAuth namespace with TypeScript type augmentation |
app/composables/useXAuth.ts | Better Auth client wrapper — all session state and auth methods |
app/components/XAuth/ | 7 auto-imported XAuth-prefixed components |
app/pages/auth/ | 7 pre-built auth pages |
app/layouts/auth.vue | Auth layout (centered card or split panel) |
app/middleware/auth.global.ts | Global route guard |
app/plugins/auth-token.ts | Token injection plugin |
app/utils/ | cookieStorage, fieldMapper utilities |
Environment Variables
| Variable | Required | Description |
|---|---|---|
NUXT_PUBLIC_AUTH_BASE_URL | Yes | Base URL of the Fastify API server (e.g. https://api.example.com) |
