
Nuxt Better Auth
- 1.7k installs
- 696 repo stars
- Updated July 27, 2026
- onmax/nuxt-skills
nuxt-better-auth implements Better Auth in Nuxt 4+ with composables, server helpers, and route protection references.
About
The nuxt-better-auth skill documents authentication for Nuxt 4+ on Better Auth via @onmax/nuxt-better-auth. It covers module installation, environment variables, useUserSession composables, signIn/signUp/signOut flows, serverAuth helpers, requireUserSession for API routes, and client/server route protection with routeRules and definePageMeta. Reference files split installation, client auth, server auth, route protection, plugins such as admin/passkey/2FA, NuxtHub database integration, clientOnly external backends, and type augmentation for AuthUser and AuthSession. The module is alpha (v0.0.2-alpha.19) and APIs may change. Pair with nuxt and nuxthub skills for broader Nuxt and database patterns.
- Documents useUserSession plus serverAuth and requireUserSession helpers.
- Covers client and server route protection via routeRules and definePageMeta.
- Integrates Better Auth plugins including admin, passkey, and 2FA.
- Includes NuxtHub database and Drizzle schema guidance with clientOnly mode.
- Splits guidance across installation, client-auth, server-auth, and plugins references.
Nuxt Better Auth by the numbers
- 1,727 all-time installs (skills.sh)
- +29 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #285 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 4, 2026 (Skillselion catalog sync)
nuxt-better-auth capabilities & compatibility
- Capabilities
- useusersession · serverauth · routerules · better auth plugins
- Use cases
- api development · frontend
What nuxt-better-auth says it does
Use when implementing auth in Nuxt apps with @onmax/nuxt-better-auth - provides useUserSession composable, server auth helpers, route protection, and Better Auth plugins integration.
npx skills add https://github.com/onmax/nuxt-skills --skill nuxt-better-authAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.7k |
|---|---|
| repo stars | ★ 696 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | onmax/nuxt-skills ↗ |
How do I add login, sessions, and protected routes to a Nuxt app with Better Auth?
Implement auth in Nuxt 4+ apps with @onmax/nuxt-better-auth: useUserSession, server helpers, route protection, and Better Auth plugins.
Who is it for?
Nuxt 4+ apps adopting @onmax/nuxt-better-auth during alpha development.
Skip if: Production-critical auth without reviewing alpha API stability.
When should I use this skill?
User configures Better Auth, protects Nuxt routes, or accesses sessions server-side.
What you get
Configured module with working sign-in flows, session access, and protected routes or APIs.
- Auth module configuration
- Protected route middleware
- Session composable integration
By the numbers
- Targets Nuxt 4+ applications
- Module version v0.0.2-alpha.19 documented as alpha
Files
Nuxt Better Auth
Authentication module for Nuxt 4+ built on Better Auth. Provides composables, server utilities, and route protection.
Alpha Status: This module is currently in alpha (v0.0.2-alpha.19) and not recommended for production use. APIs may change.
When to Use
- Installing/configuring
@onmax/nuxt-better-auth - Implementing login/signup/signout flows
- Protecting routes (client and server)
- Accessing user session in API routes
- Integrating Better Auth plugins (admin, passkey, 2FA)
- Setting up database with NuxtHub
- Using clientOnly mode for external auth backends
- Adding i18n support with
@nuxtjs/i18n
For Nuxt patterns: use nuxt skill For NuxtHub database: use nuxthub skill
Available Guidance
| File | Topics |
|---|---|
| [references/installation.md](references/installation.md) | Module setup, env vars, config files |
| [references/client-auth.md](references/client-auth.md) | useUserSession, signIn/signUp/signOut, BetterAuthState, safe redirects |
| [references/server-auth.md](references/server-auth.md) | serverAuth, getUserSession, requireUserSession |
| [references/route-protection.md](references/route-protection.md) | routeRules, definePageMeta, middleware |
| [references/plugins.md](references/plugins.md) | Better Auth plugins (admin, passkey, 2FA) |
| [references/database.md](references/database.md) | NuxtHub integration, Drizzle schema, custom tables with FKs |
| [references/client-only.md](references/client-only.md) | External auth backend, clientOnly mode, CORS |
| [references/types.md](references/types.md) | AuthUser, AuthSession, type augmentation |
Loading Files
Consider loading these reference files based on your task:
- [ ] references/installation.md - if installing or configuring the module
- [ ] references/client-auth.md - if building login/signup/signout flows
- [ ] references/server-auth.md - if protecting API routes or accessing user session server-side
- [ ] references/route-protection.md - if using routeRules or definePageMeta for auth
- [ ] references/plugins.md - if integrating Better Auth plugins (admin, passkey, 2FA)
- [ ] references/database.md - if setting up database with NuxtHub or Drizzle
- [ ] references/client-only.md - if using external auth backend with clientOnly mode
- [ ] references/types.md - if working with AuthUser, AuthSession, or type augmentation
DO NOT load all files at once. Load only what's relevant to your current task.
Key Concepts
| Concept | Description |
|---|---|
useUserSession() | Client composable - user, session, loggedIn, signIn/Out methods |
requireUserSession() | Server helper - throws 401/403 if not authenticated |
auth route mode | 'user', 'guest', { user: {...} }, or false |
serverAuth() | Get Better Auth instance in server routes |
Quick Reference
// Client: useUserSession()
const { user, loggedIn, signIn, signOut } = useUserSession()
await signIn.email({ email, password }, { onSuccess: () => navigateTo('/') })// Server: requireUserSession()
const { user } = await requireUserSession(event, { user: { role: 'admin' } })// nuxt.config.ts: Route protection
routeRules: {
'/admin/**': { auth: { user: { role: 'admin' } } },
'/login': { auth: 'guest' },
'/app/**': { auth: 'user' }
}Resources
---
_Token efficiency: Main skill ~300 tokens, each sub-file ~800-1200 tokens_
Client-Side Authentication
useUserSession()
Main composable for auth state and methods.
const {
user, // Ref<AuthUser | null>
session, // Ref<AuthSession | null>
loggedIn, // ComputedRef<boolean>
ready, // ComputedRef<boolean> - session fetch complete
client, // Better Auth client (client-side only)
signIn, // Proxy to client.signIn
signUp, // Proxy to client.signUp
signOut, // Sign out and clear session
fetchSession, // Manually refresh session
updateUser // Optimistic local user update
} = useUserSession()Sign In
// Email/password
await signIn.email({
email: 'user@example.com',
password: 'password123'
}, {
onSuccess: () => navigateTo('/dashboard')
})
// OAuth
await signIn.social({ provider: 'github' })Sign Up
await signUp.email({
email: 'user@example.com',
password: 'password123',
name: 'John Doe'
}, {
onSuccess: () => navigateTo('/welcome')
})Sign Out
await signOut()
// or with redirect
await signOut({ redirect: '/login' })Check Auth State
<script setup>
const { user, loggedIn, ready } = useUserSession()
</script>
<template>
<div v-if="!ready">Loading...</div>
<div v-else-if="loggedIn">Welcome, {{ user?.name }}</div>
<div v-else>Please log in</div>
</template>Safe Redirects
Always validate redirect URLs from query params to prevent open redirects:
function getSafeRedirect() {
const redirect = route.query.redirect as string
// Must start with / and not // (prevents protocol-relative URLs)
if (!redirect?.startsWith('/') || redirect.startsWith('//')) {
return '/'
}
return redirect
}
await signIn.email({
email, password
}, {
onSuccess: () => navigateTo(getSafeRedirect())
})Wait for Session
Useful when needing session before rendering:
await waitForSession() // 5s timeout
if (loggedIn.value) {
// Session is ready
}Manual Session Refresh
// Refetch from server
await fetchSession({ force: true })Session Management
Additional session management via Better Auth client:
const { client } = useUserSession()
// List all active sessions for current user
const sessions = await client.listSessions()
// Revoke a specific session
await client.revokeSession({ sessionId: 'xxx' })
// Revoke all sessions except current
await client.revokeOtherSessions()
// Revoke all sessions (logs out everywhere)
await client.revokeSessions()These methods require the user to be authenticated.
BetterAuthState Component
Renders once session hydration completes (ready === true), with loading placeholder support.
<BetterAuthState>
<template #default="{ loggedIn, user, session, signOut }">
<p v-if="loggedIn">Hi {{ user?.name }}</p>
<button v-else @click="navigateTo('/login')">Sign in</button>
</template>
<template #placeholder>
<p>Loading…</p>
</template>
</BetterAuthState>Slots:
default- Renders whenready === true, provides{ loggedIn, user, session, signOut }placeholder- Renders while session hydrates
Useful in clientOnly mode or for graceful SSR loading states.
Client-Only Mode (External Auth Backend)
When Better Auth runs on a separate backend (microservices, standalone server), use clientOnly mode.
Configuration
1. Enable in nuxt.config.ts
export default defineNuxtConfig({
modules: ['@onmax/nuxt-better-auth'],
auth: {
clientOnly: true,
},
})2. Point client to external server
```ts [app/auth.config.ts] import { createAuthClient } from 'better-auth/vue'
export function createAppAuthClient(_baseURL: string) { return createAuthClient({ baseURL: 'https://auth.example.com', // External auth server }) }
### 3. Set frontend URL
NUXT_PUBLIC_SITE_URL="https://your-frontend.com"
## What Changes
| Feature | Full Mode | Client-Only |
| ----------------------------------------------------------------------------- | --------------- | ----------------- |
| `server/auth.config.ts` | Required | Not needed |
| `/api/auth/**` handlers | Auto-registered | Skipped |
| `NUXT_BETTER_AUTH_SECRET` | Required | Not needed |
| Server utilities (`serverAuth()`, `getUserSession()`, `requireUserSession()`) | Available | **Not available** |
| SSR session hydration | Server-side | Client-side only |
| `useUserSession()`, route protection, `<BetterAuthState>` | Works | Works |
## CORS Requirements
Ensure external auth server:
- Allows requests from frontend (CORS with `credentials: true`)
- Uses `SameSite=None; Secure` cookies (HTTPS required)
- Includes frontend URL in `trustedOrigins`
## SSR Considerations
Session fetched client-side only:
- Server-rendered pages render as "unauthenticated" initially
- Hydrates with session data on client
- Use `<BetterAuthState>` for loading states
<BetterAuthState v-slot="{ isLoading, user }"> <div v-if="isLoading">Loading...</div> <div v-else-if="user">Welcome, {{ user.name }}</div> <div v-else>Please log in</div> </BetterAuthState>
## Use Cases
- **Microservices**: Auth service is separate deployment
- **Shared auth**: Multiple frontends share one auth backend
- **Existing backend**: Already have Better Auth server running elsewhere
- **Convex backend**: Use Convex HTTP adapter for serverless auth (since v0.0.2-alpha.16)
## Architecture Example
┌─────────────────┐ ┌─────────────────┐ │ Nuxt App │────▶│ Auth Server │ │ (clientOnly) │ │ (Better Auth) │ │ │◀────│ │ └─────────────────┘ └────────┬────────┘ │ ┌────────▼────────┐ │ Database │ └─────────────────┘
Database Integration
NuxtHub Setup
Requires NuxtHub 0.10.5+ for hub:db and hub:kv alias support.
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxthub/core', '@onmax/nuxt-better-auth'],
hub: { database: true },
auth: {
secondaryStorage: true, // Optional: KV for session caching
schema: {
usePlural: false, // user vs users
casing: 'camelCase' // camelCase or snake_case
}
}
})Schema Generation
The module auto-generates Drizzle schema from Better Auth tables using Better Auth's schema generation API. Schema available via:
import { user, session, account, verification } from '#auth/database'Creating Custom Tables with Foreign Keys
Create app tables that reference auth tables by importing schema from hub:db. NuxtHub auto-merges custom schemas with Better Auth tables.
// server/db/schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
import { schema } from 'hub:db'
export const posts = sqliteTable('posts', {
id: text('id').primaryKey(),
title: text('title').notNull(),
authorId: text('author_id').notNull()
.references(() => schema.user.id),
createdAt: integer('created_at', { mode: 'timestamp' })
.$defaultFn(() => new Date()),
})Available Auth Tables:
schema.user- User accountsschema.session- Active sessionsschema.account- OAuth provider accountsschema.verification- Email verification tokens- Plugin tables:
schema.passkey,schema.twoFactor, etc.
ID Type Matching:
- SQLite/MySQL: Use
text()orvarchar() - PostgreSQL with UUID: Use
uuid()whenadvanced.database.generateId = 'uuid'
Migrations:
npx nuxt db generate # Generate migrations
npx nuxt db migrate # Apply (auto in dev)Adding columns to auth tables: Use Better Auth's additionalFields instead of custom schemas. See Better Auth Additional Fields.
Database Dialect
Supports: sqlite, postgresql, mysql
Schema syntax adapts to dialect:
- SQLite:
integer('id').primaryKey() - PostgreSQL/MySQL:
uuid('id').primaryKey()ortext('id').primaryKey()
Schema Options
auth: {
schema: {
usePlural: true, // tables: users, sessions, accounts
casing: 'snake_case' // columns: created_at, updated_at
}
}| Option | Default | Description |
|---|---|---|
usePlural | false | Pluralize table names |
casing | 'camelCase' | Column naming convention |
Extending Schema
Add custom columns via NuxtHub's schema hooks:
// server/plugins/extend-schema.ts
export default defineNitroPlugin(() => {
useNitroApp().hooks.hook('hub:db:schema:extend', (schema) => {
// Add custom tables or extend existing
})
})Secondary Storage (KV)
Enable session caching with KV:
auth: {
secondaryStorage: true
}Requires hub.kv: true in config. Improves session lookup performance.
Server Config with DB
Database adapter injected via context:
// server/auth.config.ts
import { defineServerAuth } from '#auth/server'
export default defineServerAuth(({ db }) => ({
database: db, // Already configured when hub.database: true
emailAndPassword: { enabled: true }
}))Manual Database Setup
Without NuxtHub, configure manually:
// server/auth.config.ts
import { drizzle } from 'drizzle-orm/...'
import { defineServerAuth } from '#auth/server'
const db = drizzle(...)
export default defineServerAuth(() => ({
database: drizzleAdapter(db, { provider: 'sqlite' })
}))Migrations
Better Auth creates tables automatically on first run. For production, generate migrations:
# Using Better Auth CLI
npx better-auth generateInstallation & Configuration
Install
pnpm add @onmax/nuxt-better-auth better-authVersion Requirements:
@onmax/nuxt-better-auth:^0.0.2-alpha.19(alpha)better-auth:^1.0.0(module tested with1.4.7)@nuxthub/core:^0.10.5+(optional, for database - requires 0.10.5+ forhub:dbaliases)
Module Setup
The module auto-scaffolds server/auth.config.ts and app/auth.config.ts files during installation (since v0.0.2-alpha.15).
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@onmax/nuxt-better-auth'],
auth: {
serverConfig: 'server/auth.config', // default
clientConfig: 'app/auth.config', // default
clientOnly: false, // true for external auth backend
redirects: {
login: '/login', // redirect when auth required
guest: '/' // redirect when already logged in
}
}
})Environment Variables
# Required (min 32 chars)
# Can also be set via runtimeConfig.betterAuthSecret (takes priority)
BETTER_AUTH_SECRET=your-secret-key-at-least-32-characters
# Required in production for OAuth
NUXT_PUBLIC_SITE_URL=https://your-domain.comServer Config
// server/auth.config.ts
import { defineServerAuth } from '#auth/server'
export default defineServerAuth(({ runtimeConfig, db }) => ({
emailAndPassword: { enabled: true },
// OAuth providers
socialProviders: {
github: {
clientId: runtimeConfig.github.clientId,
clientSecret: runtimeConfig.github.clientSecret
}
},
// Session configuration (optional)
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days (default)
updateAge: 60 * 60 * 24, // Update every 24h (default)
freshAge: 60 * 60 * 24, // Consider fresh for 24h (default, 0 to disable)
cookieCache: {
enabled: true,
maxAge: 60 * 5 // 5 minutes cookie cache
}
}
}))Context available in defineServerAuth:
runtimeConfig- Nuxt runtime configdb- Database adapter (when NuxtHub enabled)
Session Options
| Option | Default | Description |
|---|---|---|
expiresIn | 604800 (7 days) | Session lifetime in seconds |
updateAge | 86400 (24 hours) | How often to refresh session expiry |
freshAge | 86400 (24 hours) | Session considered "fresh" period (0 = never) |
cookieCache.enabled | false | Enable cookie caching to reduce DB queries |
cookieCache.maxAge | 300 (5 minutes) | Cookie cache lifetime |
disableSessionRefresh | false | Disable automatic session refresh |
Client Config
// app/auth.config.ts
import { createAppAuthClient } from '#auth/client'
export default createAppAuthClient({
// Client-side plugin options (e.g., passkey, twoFactor)
})NuxtHub Integration
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxthub/core', '@onmax/nuxt-better-auth'],
hub: { database: true },
auth: {
secondaryStorage: true // Enable KV for session caching
}
})See references/database.md for schema setup.
Client-Only Mode
For external auth backends (microservices, separate servers):
// nuxt.config.ts
export default defineNuxtConfig({
auth: {
clientOnly: true, // No local auth server
}
})See references/client-only.md for full setup.
i18n Integration
For internationalization support with @nuxtjs/i18n (since v0.0.2-alpha.15):
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n', '@onmax/nuxt-better-auth'],
i18n: {
// Your i18n config
}
})The module automatically integrates with @nuxtjs/i18n when present, enabling localized auth flows and error messages.
Better Auth Plugins
The module supports all Better Auth plugins. Configure in both server and client configs.
Server Plugin Setup
// server/auth.config.ts
import { defineServerAuth } from '#auth/server'
export default defineServerAuth(({ runtimeConfig }) => ({
emailAndPassword: { enabled: true },
plugins: [
admin(),
twoFactor({ issuer: 'MyApp' }),
passkey(),
multiSession()
]
}))Client Plugin Setup
// app/auth.config.ts
import { createAppAuthClient } from '#auth/client'
import { adminClient, twoFactorClient, passkeyClient, multiSessionClient } from 'better-auth/client/plugins'
export default createAppAuthClient({
plugins: [
adminClient(),
twoFactorClient(),
passkeyClient(),
multiSessionClient()
]
})Common Plugins
Admin
Role-based access control:
// Server
import { admin } from 'better-auth/plugins'
plugins: [admin()]
// Client
import { adminClient } from 'better-auth/client/plugins'
plugins: [adminClient()]Usage:
// Protect route
await requireUserSession(event, { user: { role: 'admin' } })
// Client: set user role
await client.admin.setRole({ userId: 'xxx', role: 'admin' })Two-Factor (2FA)
// Server
import { twoFactor } from 'better-auth/plugins'
plugins: [twoFactor({ issuer: 'MyApp' })]
// Client
import { twoFactorClient } from 'better-auth/client/plugins'
plugins: [twoFactorClient()]Usage:
// Enable 2FA
const { totpURI } = await client.twoFactor.enable({ password: 'xxx' })
// Show QR code with totpURI
// Verify OTP on login
await client.twoFactor.verifyTotp({ code: '123456' })Passkey
WebAuthn/FIDO2 authentication:
// Server
import { passkey } from 'better-auth/plugins'
plugins: [passkey()]
// Client
import { passkeyClient } from 'better-auth/client/plugins'
plugins: [passkeyClient()]Usage:
// Register passkey
await client.passkey.addPasskey()
// Sign in with passkey
await signIn.passkey()Multi-Session
Allow multiple concurrent sessions:
// Server
import { multiSession } from 'better-auth/plugins'
plugins: [multiSession()]
// Client
import { multiSessionClient } from 'better-auth/client/plugins'
plugins: [multiSessionClient()]Usage:
// List all sessions
const sessions = await client.multiSession.listDeviceSessions()
// Revoke specific session
await client.multiSession.revokeSession({ sessionId: 'xxx' })Plugin Type Inference
Types from plugins are automatically inferred. See references/types.md for type augmentation.
Route Protection
Three layers of protection: route rules, page meta, and server middleware.
Route Rules (Global)
Define auth requirements in nuxt.config.ts:
export default defineNuxtConfig({
routeRules: {
'/admin/**': { auth: { user: { role: 'admin' } } },
'/dashboard/**': { auth: 'user' },
'/login': { auth: 'guest' },
'/public/**': { auth: false }
}
})Auth Modes
| Mode | Behavior |
|---|---|
'user' | Requires authenticated user |
'guest' | Only unauthenticated users (redirects logged-in users) |
{ user: {...} } | Requires user matching specific properties |
false | No protection |
Page Meta (Per-Page)
Override or define auth for specific pages:
<script setup>
// Require authentication
definePageMeta({ auth: 'user' })
</script><script setup>
// Require admin role
definePageMeta({
auth: { user: { role: 'admin' } }
})
</script><script setup>
// Guest-only (login page)
definePageMeta({ auth: 'guest' })
</script>User Property Matching
// Single value
{ auth: { user: { role: 'admin' } } }
// OR logic (array)
{ auth: { user: { role: ['admin', 'moderator'] } } }
// AND logic (multiple fields)
{ auth: { user: { role: 'admin', verified: true } } }Redirect Configuration
// nuxt.config.ts
export default defineNuxtConfig({
auth: {
redirects: {
login: '/login', // Where to redirect unauthenticated users
guest: '/dashboard' // Where to redirect logged-in users from guest pages
}
}
})Server Middleware
Auth middleware runs on all /api/** routes matching routeRules.
For custom API protection, use requireUserSession():
// server/api/admin/[...].ts
export default defineEventHandler(async (event) => {
await requireUserSession(event, { user: { role: 'admin' } })
// Handle request
})Priority Order
1. definePageMeta({ auth }) - highest priority 2. routeRules patterns - matched by path 3. Default: no protection
Prerendered Pages
Auth checks skip during prerender hydration. Session fetched client-side after hydration completes.
Server-Side Authentication
serverAuth()
Get the Better Auth instance for advanced operations:
// server/api/custom.ts
export default defineEventHandler(async (event) => {
const auth = serverAuth()
// Access full Better Auth API
const sessions = await auth.api.listSessions({ headers: event.headers })
return sessions
})Module-level singleton (safe to call multiple times - returns cached instance).
Available Server Methods
Via serverAuth().api:
const auth = serverAuth()
// Session management
await auth.api.listSessions({ headers: event.headers })
await auth.api.revokeSession({ sessionId: 'xxx' }, { headers: event.headers })
await auth.api.revokeOtherSessions({ headers: event.headers })
await auth.api.revokeSessions({ headers: event.headers })
// User management (with admin plugin)
await auth.api.setRole({ userId: 'xxx', role: 'admin' }, { headers: event.headers })getUserSession()
Get current session without throwing (returns null if not authenticated):
export default defineEventHandler(async (event) => {
const result = await getUserSession(event)
if (!result) {
return { guest: true }
}
return { user: result.user }
})Returns { user: AuthUser, session: AuthSession } | null.
requireUserSession()
Enforce authentication - throws if not authenticated:
export default defineEventHandler(async (event) => {
const { user, session } = await requireUserSession(event)
// user and session are guaranteed to exist
return { userId: user.id }
})- Throws
401if not authenticated - Throws
403if user matching fails
User Matching
Restrict access based on user properties:
// Single value - exact match
await requireUserSession(event, {
user: { role: 'admin' }
})
// Array - OR logic (any value matches)
await requireUserSession(event, {
user: { role: ['admin', 'moderator'] }
})
// Multiple fields - AND logic (all must match)
await requireUserSession(event, {
user: { role: 'admin', verified: true }
})Custom Rules
For complex validation logic:
await requireUserSession(event, {
rule: ({ user, session }) => {
return user.subscription?.active && user.points > 100
}
})
// Combined with user matching
await requireUserSession(event, {
user: { verified: true },
rule: ({ user }) => user.subscription?.plan === 'pro'
})Pattern Examples
// Admin-only endpoint
export default defineEventHandler(async (event) => {
const { user } = await requireUserSession(event, {
user: { role: 'admin' }
})
return getAdminData()
})
// Premium feature
export default defineEventHandler(async (event) => {
await requireUserSession(event, {
rule: ({ user }) => ['pro', 'enterprise'].includes(user.plan)
})
return getPremiumContent()
})
// Owner-only resource
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id')
const { user } = await requireUserSession(event)
const resource = await getResource(id)
if (resource.ownerId !== user.id) {
throw createError({ statusCode: 403 })
}
return resource
})TypeScript Types
Module Alias
Import types from the module alias:
import type { AuthUser, AuthSession, ServerAuthContext, AppAuthClient } from '#nuxt-better-auth'Core Types
AuthUser
User object returned by useUserSession() and requireUserSession():
interface AuthUser {
id: string
email: string
name?: string
image?: string
emailVerified: boolean
createdAt: Date
updatedAt: Date
// Plus any fields from plugins (role, etc.)
}AuthSession
Session object:
interface AuthSession {
id: string
userId: string
expiresAt: Date
// token is filtered from exposed data
}Type Inference
Types are automatically inferred from your server config. The module uses InferUser and InferSession from Better Auth:
// Inferred from server/auth.config.ts
type AuthUser = InferUser<typeof authConfig>
type AuthSession = InferSession<typeof authConfig>Plugin Type Augmentation
When using plugins, types extend automatically:
// With admin plugin
interface AuthUser {
// ... base fields
role: 'user' | 'admin'
}
// With 2FA plugin
interface AuthUser {
// ... base fields
twoFactorEnabled: boolean
}ServerAuthContext
Available in defineServerAuth() callback:
interface ServerAuthContext {
runtimeConfig: RuntimeConfig
db?: DrizzleDatabase // When NuxtHub enabled
}Using Types in Components
<script setup lang="ts">
import type { AuthUser } from '#nuxt-better-auth'
const { user } = useUserSession()
// user is Ref<AuthUser | null>
function greet(u: AuthUser) {
return `Hello, ${u.name}`
}
</script>Using Types in Server
// server/utils/helpers.ts
import type { AuthUser, AuthSession } from '#nuxt-better-auth'
export function isAdmin(user: AuthUser): boolean {
return user.role === 'admin'
}Custom User Fields
Extend user type via Better Auth config:
// server/auth.config.ts
export default defineServerAuth(() => ({
user: {
additionalFields: {
plan: { type: 'string' },
credits: { type: 'number' }
}
}
}))Types automatically include these fields:
// AuthUser now includes:
interface AuthUser {
// ... base fields
plan: string
credits: number
}Type-Safe User Matching
// Fully typed
await requireUserSession(event, {
user: { role: 'admin' } // TypeScript knows valid fields
})Related skills
How it compares
Pick nuxt-better-auth for Better Auth on Nuxt 4+ prototypes; pick generic auth skills for Next.js or stable production auth modules.
FAQ
What is nuxt-better-auth?
Implement auth in Nuxt 4+ apps with @onmax/nuxt-better-auth: useUserSession, server helpers, route protection, and Better Auth plugins.
What is nuxt-better-auth?
Implement auth in Nuxt 4+ apps with @onmax/nuxt-better-auth: useUserSession, server helpers, route protection, and Better Auth plugins.
What is nuxt-better-auth?
Implement auth in Nuxt 4+ apps with @onmax/nuxt-better-auth: useUserSession, server helpers, route protection, and Better Auth plugins.
Is Nuxt Better Auth safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.