X Enterprises

nuxt-x-neon-auth

Neon Auth authentication layer for Nuxt — pre-built auth pages, components, composables, and global route middleware backed by Neon Auth (Better Auth).

nuxt-x-neon-auth

Authentication layer for Nuxt 4 using Neon Auth (Better Auth). Provides pre-built auth pages, 10 components, two composables (useXAuth and useXNeonAuth), and a global route middleware. Supports email/password, OAuth, OTP, and magic links.

Installation

npm install @xenterprises/nuxt-x-neon-auth

What the consumer writes

The layer ships batteries included: auth pages, route middleware, an auth layout, and all components/composables are auto-registered. The minimal consumer is three things — an extends entry, an app/app.config.ts, and one env var.

// nuxt.config.ts
export default defineNuxtConfig({
  extends: ["@xenterprises/nuxt-x-neon-auth"],
});
// app/app.config.ts — must live in app/, not the project root
export default defineAppConfig({
  xAuth: {
    redirects: {
      login: "/auth/login",
      afterLogin: "/",
      afterLogout: "/auth/login",
    },
    features: {
      oauth: false,
      magicLink: false,
      otp: false,
      forgotPassword: true,
    },
    socialLoginProviders: ["google", "github"],
  },
});
# .env — your Neon Auth endpoint
NUXT_PUBLIC_NEON_AUTH_URL=https://your-project.neonauth.xxx.neon.tech/your-db/auth

Everything above is optional except NUXT_PUBLIC_NEON_AUTH_URL — the layer's own app.config.ts carries working defaults (forgotPassword enabled, OAuth/magic link/OTP disabled, providers falling back to ["google"]). Every default page and redirect is overridable via the xAuth namespace or standard Nuxt page overriding.

Requirements and notes:

  • SPA mode. The layer sets ssr: false — Neon Auth relies on browser APIs. Do not re-enable SSR in the consumer.
  • Peer dependencies: nuxt ^4.0.0, @nuxt/ui ^4.0.0, tailwindcss ^4.0.0, @tailwindcss/vite ^4.0.0.
  • Beta upstream dependency. The auth client is @neondatabase/neon-js (^0.1.0-beta.15), which is beta-only upstream — no stable release exists yet (as of 2026-07 this is an accepted exception). This blocks the layer from the coordinated 2.0 stable line until neon-js ships a stable release. Expect possible breaking changes between neon-js betas on version bumps.
  • Breaking (v0.4.0): ui.colors.gray was renamed to ui.colors.neutral (Nuxt UI v4 dropped the gray color key). If your app.config.ts sets ui.colors.gray, rename it to ui.colors.neutral.

What This Layer Provides

Configuration (app.config.ts)

OptionTypeDefaultDescription
redirects.loginstring"/auth/login"Login page path.
redirects.signupstring"/auth/signup"Signup page path.
redirects.afterLoginstring"/"Redirect after login.
redirects.afterSignupstring"/"Redirect after signup.
redirects.afterLogoutstring"/auth/login"Redirect after logout.
features.oauthbooleanfalseEnable OAuth/social login.
features.magicLinkbooleanfalseEnable magic link auth.
features.otpbooleanfalseEnable OTP auth.
features.forgotPasswordbooleantrueEnable password reset.
socialLoginProvidersOAuthProvider[]undefined (falls back to ["google"])OAuth providers to display.
publicRoutesstring[][]Extra routes the global middleware treats as public (exact path or prefix), e.g. ["/docs", "/pricing"].

useXAuth() Composable

High-level composable with toast notifications, loading states, and automatic navigation.

Property / MethodTypeDescription
user() => Promise<User | null>Get current user.
isLoadingRef<boolean>Loading state.
isAuthenticatedRef<boolean>Auth status (call checkAuth() first).
emailSentRef<boolean>Whether an email was sent (magic link / forgot password).
codeSentRef<boolean>Whether an OTP code was sent.
checkAuth()Promise<User | null>Check auth status and update isAuthenticated.
login(email, password)Promise<User | null>Sign in with credentials.
signup(email, password)Promise<User | null>Create account.
logout()Promise<boolean>Sign out.
forgotPassword(email)Promise<boolean>Send password reset email.
resetPassword(code, password)Promise<true | {error}>Reset password with token.
loginWithProvider(provider)Promise<boolean>OAuth sign in.
loginWithOAuth(provider)Promise<boolean>Alias of loginWithProvider (used by the shipped components).
sendOtp(email)Promise<boolean>Send OTP code.
verifyOtp(code)Promise<User | null>Verify OTP code.
sendMagicLink(email)Promise<boolean>Send magic link email.
handleMagicLinkCallback(token)Promise<true | {error}>Verify magic link token.
changePassword(current, new)Promise<boolean>Change password (authenticated).
updateUser({name?, image?})Promise<boolean>Update user profile.
deleteAccount(password)Promise<boolean>Delete user account.
resetState()voidReset emailSent and codeSent.
authClientobjectDirect access to Neon Auth client.

useXNeonAuth() Composable

Lower-level composable wrapping the Neon Auth client with Vue reactivity. Returns { status: "ok", data? } or { status: "error", error: { message } }.

MethodDescription
currentUser()Get current session user.
userAlias of currentUser().
getSession()Raw authClient.getSession() result (session + user).
signInWithCredential(email, password)Sign in with email/password.
signUpWithCredential(email, password, name?)Create account.
signOut()Sign out.
signInWithOAuth(provider, options?)OAuth sign in.
sendOtpCode(email)Send OTP verification code.
verifyOtpCode(otp)Verify OTP code.
sendMagicLinkEmail(email, options?)Send magic link.
verifyMagicLink(token)Verify magic link token.
sendForgotPasswordEmail(email)Send password reset email.
changePassword(current, new)Change password.
updateUser({name?, image?})Update profile.
deleteAccount(password)Delete account.
authClientRaw Neon Auth client.

Components

ComponentDescription
XAuthLoginLogin form with email/password, OAuth, OTP/magic link links.
XAuthSignupSignup form with email/password and OAuth.
XAuthForgotPasswordPassword reset request form.
XAuthMagicLinkMagic link email form.
XAuthOtpOTP email + code verification form.
XAuthMagicLinkCallbackMagic link token verification handler.
XAuthOAuthButtonSingle OAuth provider button with inline SVG icons.
XAuthOAuthButtonGroupGroup of OAuth buttons from config.
XAuthErrorBoundaryError display with optional retry.
XAuthHandlerGeneric auth callback handler (magic-link, password-reset, oauth, email-verification).

XAuthHandler Props

PropTypeDefaultDescription
type"magic-link" | "password-reset" | "oauth" | "email-verification"requiredHandler type.
redirectTostring"/"Redirect after success.
redirectDelaynumber1500Delay before redirect (ms).

Auto-Registered Pages

PathDescription
/auth/loginLogin page.
/auth/signupSignup page.
/auth/forgot-passwordPassword reset request.
/auth/magic-linkMagic link sign in.
/auth/otpOTP sign in.
/auth/logoutLogout page.
/auth/handler/[slug]Auth callback handler.

Route Protection

The global middleware runs on every navigation:

  • Redirects authenticated users away from /auth/* to home.
  • Redirects unauthenticated users from protected pages to /auth/login.
  • Allows unauthenticated access to /handler/* callback routes.

Environment Variables

VariableRequiredDescription
NUXT_PUBLIC_NEON_AUTH_URLYesNeon Auth endpoint URL (e.g. https://your-project.neonauth.xxx.neon.tech/your-db/auth).

Supported OAuth Providers

Google, GitHub, Apple, Microsoft, Discord, Facebook, Twitter, LinkedIn, GitLab, Spotify, Twitch, Slack, Notion, Linear, Figma, Atlassian, Salesforce, Cognito, and 30+ more via Better Auth.

Error Reference

useXAuth() methods show toast notifications on error. useXNeonAuth() returns structured errors:

ErrorContext
"No OTP session found"verifyOtpCode called without sending a code first.
"Invalid credentials"Wrong email or password.
"Email already exists"Account already registered.
"Token expired"Auth token expired (magic link or password reset).
"Incorrect password"Current password wrong in changePassword.

How It Works

useXNeonAuth() creates a client via createAuthClient() from @neondatabase/neon-js/auth, pointing to your Neon Auth endpoint. useXAuth() wraps it with loading states, toast notifications (Nuxt UI), and automatic navigation after auth events. The global middleware checks session status via currentUser() on every route change. Pre-built pages render the matching component using the auth layout (centered card on a neutral-toned background). Components are built with Nuxt UI v4 and use Zod for form validation.

Copyright © 2026