npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xenterprises/nuxt-x-auth

v0.2.1

Published

Authentication layer for Nuxt with multi-provider support (Stack Auth, Better Auth, Local JWT)

Downloads

24

Readme

@xenterprises/nuxt-x-auth

Universal authentication layer for Nuxt 4 with multi-provider support. Drop-in auth pages, components, and composables that work with Stack Auth, Better Auth, Neon Auth, or a custom JWT backend.

Install

npm install @xenterprises/nuxt-x-auth

Quick Start

// nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@xenterprises/nuxt-x-auth']
})
// app.config.ts
export default defineAppConfig({
  xAuth: {
    provider: 'stack', // 'stack' | 'better-auth' | 'neon-auth' | 'local'
  }
})
<script setup>
const { user, login, logout, isAuthenticated } = useXAuth()

await login('[email protected]', 'password')
</script>

Options (app.config.ts)

| Option | Type | Default | Required | Description | |--------|------|---------|----------|-------------| | provider | 'stack' \| 'better-auth' \| 'neon-auth' \| 'local' | 'stack' | Yes | Auth provider to use | | tokens.accessCookie | string | 'x_auth_access' | No | Cookie name for access token | | tokens.refreshCookie | string | 'x_auth_refresh' | No | Cookie name for refresh token | | tokens.hasRefresh | boolean | true | No | Whether provider supports refresh tokens | | redirects.login | string | '/auth/login' | No | Login page path | | redirects.signup | string | '/auth/signup' | No | Signup page path | | redirects.afterLogin | string | '/' | No | Redirect after login | | redirects.afterSignup | string | '/' | No | Redirect after signup | | redirects.afterLogout | string | '/auth/login' | No | Redirect after logout | | redirects.forgotPassword | string | '/auth/forgot-password' | No | Forgot password path | | features.oauth | boolean | false | No | Enable OAuth buttons | | features.magicLink | boolean | false | No | Enable magic link auth | | features.otp | boolean | false | No | Enable OTP auth | | features.forgotPassword | boolean | true | No | Show forgot password link | | features.signup | boolean | true | No | Show signup link | | oauthProviders | Array<{id, label, icon}> | [] | No | OAuth providers to display | | fieldMapping.id | string | provider-specific | No | Field name for user ID | | fieldMapping.name | string | provider-specific | No | Field name for display name | | fieldMapping.avatar | string | provider-specific | No | Field name for avatar URL | | fieldMapping.emailVerified | string | provider-specific | No | Field name for email verified flag | | ui.showLogo | boolean | true | No | Show logo on auth pages | | ui.logoUrl | string | '' | No | Logo image URL | | ui.brandName | string | '' | No | Brand name for alt text | | ui.tagline | string | '' | No | Tagline below brand name | | ui.layout | 'centered' \| 'split' | 'centered' | No | Auth page layout style | | ui.form.icon | string | '' | No | Icon above form title | | ui.form.showSeparator | boolean | true | No | Show "or" separator between OAuth and form |

Composable: useXAuth()

Auto-imported. Returns:

| Property | Type | Description | |----------|------|-------------| | user | Ref<AuthUser \| null> | Current authenticated user | | isLoading | Ref<boolean> | Loading state | | isAuthenticated | ComputedRef<boolean> | Whether user is logged in | | emailSent | Ref<boolean> | Email sent state (forgot password, magic link) | | codeSent | Ref<boolean> | Code sent state (OTP) | | config | ComputedRef<AuthConfig> | Current auth config | | providerType | string | Active provider type | | login(email, password) | Promise<AuthUser \| null> | Login with credentials | | signup(email, password) | Promise<AuthUser \| null> | Create account | | logout() | Promise<boolean> | Sign out | | forgotPassword(email) | Promise<boolean> | Send reset email | | resetPassword(code, newPassword) | Promise<true \| {error}> | Reset password | | loginWithProvider(name, options?) | Promise<boolean> | OAuth login | | sendOtp(email) | Promise<boolean> | Send OTP code | | verifyOtp(code) | Promise<AuthUser \| null> | Verify OTP | | sendMagicLink(email, options?) | Promise<boolean> | Send magic link | | handleMagicLinkCallback(code) | Promise<true \| {error}> | Handle magic link callback | | getCurrentUser() | Promise<AuthUser \| null> | Refresh user from provider | | getToken() | Promise<string \| null> | Get access token | | getAuthHeaders() | Promise<Record<string, string>> | Get auth headers for API calls | | resetState() | void | Reset emailSent/codeSent |

Normalized User Object

All providers return a normalized AuthUser:

interface AuthUser {
  id: string
  email: string
  name: string
  avatar?: string
  emailVerified: boolean
  metadata?: Record<string, any>
}

Field mapping is automatic per provider with fallback chains. Override via fieldMapping in config.

Components

| Component | Description | |-----------|-------------| | XAuthForm | Base form component with fields, OAuth providers, and footer slot | | XAuthLogin | Login form with email/password, OAuth, links to signup/forgot/OTP/magic | | XAuthSignup | Signup form with email/password and OAuth | | XAuthForgotPassword | Password reset request form with success state | | XAuthOtp | Two-step OTP flow: email input, then code verification | | XAuthMagicLink | Magic link request form with success state | | XAuthHandler | Callback handler for OAuth, magic link, password reset, email verification | | XAuthMagicLinkCallback | Standalone magic link callback handler | | XAuthOAuthButton | Single OAuth provider button with inline SVG icons | | XAuthOAuthButtonGroup | All configured OAuth buttons grouped |

Pages (Auto-registered)

| Path | Description | Access | |------|-------------|--------| | /auth/login | Login page | Guest only | | /auth/signup | Registration page | Guest only | | /auth/forgot-password | Password reset request | Guest only | | /auth/otp | OTP authentication | Guest only | | /auth/magic-link | Magic link authentication | Guest only | | /auth/logout | Logout handler | Public | | /auth/handler/[...slug] | OAuth/callback handler | Public |

Route Protection

The global middleware (auth.global.ts) automatically protects routes:

  • Guest-only: /auth/login, /auth/signup, /auth/forgot-password, /auth/magic-link, /auth/otp — authenticated users are redirected to afterLogin
  • Public: /auth/handler/*, /auth/logout — accessible by anyone
  • Protected: Everything else — unauthenticated users are redirected to login

Environment Variables

Stack Auth

| Variable | Required | Description | |----------|----------|-------------| | NUXT_PUBLIC_STACK_PROJECT_ID | Yes | Stack Auth project ID | | NUXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY | Yes | Stack Auth publishable key |

Better Auth

| Variable | Required | Description | |----------|----------|-------------| | NUXT_PUBLIC_BETTER_AUTH_BASE_URL | Yes | Better Auth API base URL |

Neon Auth

| Variable | Required | Description | |----------|----------|-------------| | NUXT_PUBLIC_NEON_AUTH_PROJECT_ID | Yes | Neon project ID | | NUXT_PUBLIC_NEON_AUTH_BRANCH_ID | No | Neon branch ID for branch-aware auth | | NUXT_PUBLIC_NEON_AUTH_BASE_URL | No | Override base URL (default: https://{projectId}.auth.neon.tech) |

Local JWT

| Variable | Required | Description | |----------|----------|-------------| | NUXT_PUBLIC_LOCAL_AUTH_BASE_URL | Yes | API base URL | | NUXT_PUBLIC_LOCAL_AUTH_LOGIN_ENDPOINT | No | Login endpoint (default: /auth/login) | | NUXT_PUBLIC_LOCAL_AUTH_SIGNUP_ENDPOINT | No | Signup endpoint (default: /auth/signup) | | NUXT_PUBLIC_LOCAL_AUTH_LOGOUT_ENDPOINT | No | Logout endpoint (default: /auth/logout) | | NUXT_PUBLIC_LOCAL_AUTH_REFRESH_ENDPOINT | No | Token refresh endpoint (default: /auth/refresh) | | NUXT_PUBLIC_LOCAL_AUTH_USER_ENDPOINT | No | User info endpoint (default: /auth/me) |

Providers

Stack Auth

Full-featured auth with OAuth, MFA, magic links, and OTP. Uses Stack's built-in cookie-based token storage. Supports all authentication methods.

Better Auth

Open-source auth framework. Self-hosted or cloud. Supports email/password, OAuth, and magic links. Uses cookie storage via this layer.

Neon Auth

Neon's managed Better Auth service. Adds branch-aware authentication via X-Neon-Branch-Id header. Same API as Better Auth with project-scoped endpoints.

Local JWT

Custom JWT backend. Fully configurable endpoints. Supports access + refresh tokens with automatic retry on 401. Uses cookie storage via this layer.

Token Storage

Tokens are stored in cookies with secure defaults:

  • SameSite=Lax — CSRF protection
  • Secure flag in production — HTTPS only
  • Access token: 1 hour expiry
  • Refresh token: 7 day expiry

Cookie names are configurable via tokens.accessCookie and tokens.refreshCookie.

How It Works

  1. Provider abstraction: useXAuth() selects a provider based on app.config.ts and delegates all auth operations to it. Each provider implements the AuthProvider interface.

  2. Field normalization: Raw user objects from each provider are normalized to a unified AuthUser format using normalizeUser(). Provider-specific field names (e.g. displayName vs name) are resolved via default mappings and configurable fallback chains.

  3. Cookie storage: useCookieStorage() wraps Nuxt's useCookie to manage access/refresh tokens with secure defaults. Used by Better Auth, Neon Auth, and Local JWT providers.

  4. Global middleware: auth.global.ts runs on every navigation. It classifies routes as guest-only, public, or protected, then checks authentication state via getCurrentUser() and redirects accordingly.

  5. Auth token plugin: Provides $getAuthToken via Nuxt plugin so other layers (e.g. nuxt-x-app) can make authenticated API calls without coupling to a specific auth provider.

Layer Architecture

  • nuxt.config.ts: Registers @nuxt/ui, defines runtimeConfig.public for all provider credentials, includes base CSS.
  • app.config.ts: Defines all configurable options (provider, tokens, redirects, features, UI). Consumer apps override these in their own app.config.ts.
  • app/: Contains all components, composables, pages, layouts, middleware, plugins, and utilities.

Requirements

  • Nuxt 4+
  • @nuxt/ui v4+ (included as dependency)
  • better-auth (optional peer dependency, only needed for Better Auth provider)

License

UNLICENSED