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-local

v0.2.1

Published

Local JWT authentication layer for Nuxt with custom backend support

Readme

@xenterprises/nuxt-x-auth-local

Local JWT authentication layer for Nuxt 4 — works with any backend that speaks JWT.

Install

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

Quick Start

// nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@xenterprises/nuxt-x-auth-local']
})
NUXT_PUBLIC_LOCAL_AUTH_BASE_URL=https://api.example.com

That's it. The layer provides login, signup, forgot-password, reset-password pages and a global auth middleware out of the box.

Environment Variables

| Name | Required | Default | Description | |------|----------|---------|-------------| | NUXT_PUBLIC_LOCAL_AUTH_BASE_URL | Yes | "" | Base URL of your backend API | | NUXT_PUBLIC_LOCAL_AUTH_LOGIN_ENDPOINT | No | /auth/login | Login endpoint path | | NUXT_PUBLIC_LOCAL_AUTH_SIGNUP_ENDPOINT | No | /auth/signup | Signup endpoint path | | NUXT_PUBLIC_LOCAL_AUTH_LOGOUT_ENDPOINT | No | /auth/logout | Logout endpoint path | | NUXT_PUBLIC_LOCAL_AUTH_REFRESH_ENDPOINT | No | /auth/refresh | Token refresh endpoint path | | NUXT_PUBLIC_LOCAL_AUTH_USER_ENDPOINT | No | /auth/me | Current user endpoint path | | NUXT_PUBLIC_LOCAL_AUTH_FORGOT_PASSWORD_ENDPOINT | No | /auth/forgot-password | Forgot password endpoint | | NUXT_PUBLIC_LOCAL_AUTH_RESET_PASSWORD_ENDPOINT | No | /auth/reset-password | Reset password endpoint | | NUXT_PUBLIC_LOCAL_AUTH_CHANGE_PASSWORD_ENDPOINT | No | /auth/change-password | Change password endpoint |

Configuration (app.config.ts)

export default defineAppConfig({
  xAuth: {
    tokens: {
      accessCookie: 'x_auth_access',   // Cookie name for access token
      refreshCookie: 'x_auth_refresh', // Cookie name for refresh token
      hasRefresh: true,                // Enable refresh token flow
    },
    redirects: {
      login: '/auth/login',
      signup: '/auth/signup',
      afterLogin: '/dashboard',
      afterSignup: '/dashboard',
      afterLogout: '/auth/login',
      forgotPassword: '/auth/forgot-password',
      resetPassword: '/auth/reset-password',
    },
    features: {
      forgotPassword: true,  // Show forgot password link
      signup: true,          // Show signup link on login
    },
    ui: {
      showLogo: true,
      logoUrl: '/logo.svg',
      brandName: 'My App',
      tagline: '',
      layout: 'centered',     // 'centered' | 'split'
      background: {
        type: 'gradient',      // 'gradient' | 'image' | 'solid'
        imageUrl: '',
        overlayOpacity: 50,
      },
      card: {
        glass: false,
        glassIntensity: 'medium', // 'subtle' | 'medium' | 'strong'
      },
      split: {
        heroPosition: 'left',
        heroImageUrl: '',
        headline: '',
        subheadline: '',
        features: [],
      },
      form: {
        icon: '',
        showSeparator: true,
      },
    },
  },
})

Composable: useXAuth()

Auto-imported. State is shared across all components via useState.

<script setup>
const {
  user,              // Ref<AuthUser | null>
  isLoading,         // Ref<boolean>
  isAuthenticated,   // ComputedRef<boolean>
  emailSent,         // Ref<boolean>
  config,            // ComputedRef<AuthConfig>
  login,             // (email, password) => Promise<AuthUser | null>
  signup,            // (email, password) => Promise<AuthUser | null>
  logout,            // () => Promise<true>
  forgotPassword,    // (email) => Promise<boolean>
  resetPassword,     // (token, newPassword) => Promise<true | { error: string }>
  changePassword,    // (currentPassword, newPassword) => Promise<true | { error: string }>
  refreshToken,      // () => Promise<AuthTokens | null>
  getCurrentUser,    // () => Promise<AuthUser | null>
  getToken,          // () => string | null
  getAuthHeaders,    // () => Record<string, string>
  resetState,        // () => void
} = useXAuth()
</script>

Methods

| Method | Args | Returns | Description | |--------|------|---------|-------------| | login | email: string, password: string | Promise<AuthUser \| null> | Authenticates and redirects to afterLogin | | signup | email: string, password: string | Promise<AuthUser \| null> | Creates account and redirects to afterSignup | | logout | — | Promise<true> | Clears tokens and redirects to afterLogout | | forgotPassword | email: string | Promise<boolean> | Sends reset email (always shows success to prevent enumeration) | | resetPassword | token: string, newPassword: string | Promise<true \| { error }> | Resets password using email token | | changePassword | currentPassword: string, newPassword: string | Promise<true \| { error }> | Changes password for authenticated user | | refreshToken | — | Promise<AuthTokens \| null> | Manually refresh the access token | | getCurrentUser | — | Promise<AuthUser \| null> | Fetches current user from API | | getToken | — | string \| null | Returns current access token | | getAuthHeaders | — | Record<string, string> | Returns { Authorization: 'Bearer ...' } or {} | | resetState | — | void | Resets emailSent flag |

Components

| Component | Description | |-----------|-------------| | XAuthForm | Base form component with fields, validation, password toggle | | XAuthLogin | Login form with email/password, signup link, forgot password link | | XAuthSignup | Signup form with email/password, login link, terms footer | | XAuthForgotPassword | Forgot password form with email sent confirmation state |

XAuthForm Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | icon | string | — | Lucide icon name for form header | | title | string | — | Form title | | description | string | — | Description text below title | | fields | Array<{ name, type, label, placeholder, required }> | [] | Form fields | | submit | { label: string } | { label: 'Continue' } | Submit button config | | schema | ZodObject | — | Zod validation schema | | loading | boolean | false | Loading state |

XAuthForm Slots

| Slot | Description | |------|-------------| | description | Custom description content | | password-hint | Hint below password fields (e.g., forgot password link) | | footer | Footer content below submit button |

XAuthForm Events

| Event | Payload | Description | |-------|---------|-------------| | submit | { data: Record<string, any> } | Emitted on valid form submission |

Pages (Auto-registered)

| Route | Description | |-------|-------------| | /auth/login | Login page | | /auth/signup | Registration page | | /auth/forgot-password | Forgot password request | | /auth/reset-password?token=... | Password reset (requires token query param) | | /auth/logout | Logout handler |

Route Protection

The global middleware (auth.global.ts) handles three route types:

  • Guest-only: /auth/login, /auth/signup, /auth/forgot-password, /auth/reset-password — redirects authenticated users to afterLogin
  • Public: /auth/logout — accessible by anyone
  • Protected: Everything else — redirects unauthenticated users to login

Token Storage

Tokens are stored in Nuxt cookies (useCookie):

  • SameSite=Lax for CSRF protection
  • Secure flag in production (HTTPS only)
  • Access token: 1 hour max-age
  • Refresh token: 7 day max-age
  • Cookie names are configurable via xAuth.tokens

User Normalization

The layer normalizes user objects from any backend shape. It supports these field name fallbacks:

| Field | Fallback chain | |-------|---------------| | id | id, sub, user_id, userId, _id | | email | email, primaryEmail, emailAddress | | name | name, displayName, full_name, fullName, username | | avatar | avatar, avatarUrl, image, profile_picture, photo | | emailVerified | emailVerified, email_verified, verified, isVerified | | metadata | metadata, customData |

API Requirements

Your backend must implement these endpoints (paths are configurable):

POST /auth/login

// Request
{ "email": "[email protected]", "password": "password123" }
// Response
{ "accessToken": "jwt-token", "refreshToken": "refresh-token" }

POST /auth/signup

// Request
{ "email": "[email protected]", "password": "password123" }
// Response
{ "accessToken": "jwt-token", "refreshToken": "refresh-token" }

GET /auth/me

Headers: Authorization: Bearer <accessToken>

// Response
{ "id": "user-123", "email": "[email protected]", "name": "John Doe" }

POST /auth/refresh

// Request
{ "refreshToken": "refresh-token" }
// Response
{ "accessToken": "new-token", "refreshToken": "new-refresh" }

POST /auth/logout

Headers: Authorization: Bearer <accessToken>

POST /auth/forgot-password

// Request
{ "email": "[email protected]" }

POST /auth/reset-password

// Request
{ "token": "reset-token", "password": "newPassword123" }

POST /auth/change-password

Headers: Authorization: Bearer <accessToken>

// Request
{ "currentPassword": "old", "newPassword": "new" }

Error Reference

All errors are shown via useToast() with appropriate titles:

| Context | Toast Title | When | |---------|-------------|------| | Login | "Sign In Failed" | Invalid credentials, network error, empty input | | Signup | "Sign Up Failed" | Email taken, network error, empty input | | Forgot Password | "Password Reset Failed" | Empty email | | Change Password | "Change Password Failed" | Missing input, API error |

Security

  • Open redirect protection: All redirect paths are validated — only relative paths starting with / are allowed. Protocol-relative (//evil.com) and absolute URLs (https://evil.com) are blocked.
  • Email enumeration prevention: forgotPassword always shows success, even on API errors.
  • Auto-retry on 401: If an API call returns 401, the layer attempts a token refresh and retries the request once.

How It Works

  1. Plugin (auth-token.ts): Provides $getAuthToken for other layers/plugins to access the current JWT.
  2. Middleware (auth.global.ts): Runs on every navigation. Calls getCurrentUser() to check auth state. Routes are classified as guest-only, public, or protected.
  3. Cookie Storage (cookieStorage.ts): Wraps useCookie with typed access/refresh token management.
  4. Field Mapper (fieldMapper.ts): Normalizes any backend user shape to the standard AuthUser interface using fallback field chains.
  5. Composable (useXAuth.ts): Central auth logic. Uses useState for shared state across components. Handles login/signup/logout flows, token refresh with auto-retry, and password reset.
  6. Components: XAuthForm is the base form with field rendering and Zod validation. XAuthLogin, XAuthSignup, XAuthForgotPassword compose it with pre-configured fields.

Layer Architecture

  • nuxt.config.ts: Registers @nuxt/ui, sets runtime config defaults for all endpoint paths, disables SSR.
  • app.config.ts: UI and behavior configuration (tokens, redirects, features, visual settings). Override in consumer app.
  • app/: All auto-imported composables, components, pages, layouts, plugins, and utilities.

Requirements

  • Nuxt 4+
  • A backend API implementing JWT authentication

License

UNLICENSED