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

@habityzer/nuxt-kinde-auth

v1.2.2

Published

Kinde authentication module for Nuxt 4

Readme

@habityzer/nuxt-kinde-auth

Kinde authentication module for Nuxt 4

A plug-and-play authentication module for Nuxt 4 that integrates Kinde OAuth authentication with minimal setup.

Features

Easy Setup - Add authentication to your Nuxt 4 app in minutes
OAuth 2.0 - Secure authentication flow via Kinde
Session Management - Cookie-based sessions with configurable options
Route Protection - Optional global middleware to protect routes
TypeScript - Full TypeScript support with type definitions
Server-Side Ready - SSR-compatible authentication
Debug Tools - Built-in debug endpoints for development

Installation

# Using pnpm (recommended)
pnpm add @habityzer/nuxt-kinde-auth

# Using npm
npm install @habityzer/nuxt-kinde-auth

# Using yarn
yarn add @habityzer/nuxt-kinde-auth

Quick Start

1. Add Module to Nuxt Config

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@habityzer/nuxt-kinde-auth'],
  
  kindeAuth: {
    authDomain: process.env.NUXT_KINDE_AUTH_DOMAIN,
    clientId: process.env.NUXT_KINDE_CLIENT_ID,
    clientSecret: process.env.NUXT_KINDE_CLIENT_SECRET,
    redirectURL: process.env.NUXT_KINDE_REDIRECT_URL,
    logoutRedirectURL: '/',
    postLoginRedirectURL: '/dashboard'
  }
})

2. Set Environment Variables

# .env
NUXT_KINDE_AUTH_DOMAIN=https://yourapp.kinde.com
NUXT_KINDE_CLIENT_ID=your_client_id
NUXT_KINDE_CLIENT_SECRET=your_client_secret
NUXT_KINDE_REDIRECT_URL=http://localhost:3000/api/kinde/callback
NUXT_KINDE_LOGOUT_REDIRECT_URL=http://localhost:3000

3. Use the Composable

<script setup lang="ts">
const { isAuthenticated, user, login, logout } = useKindeAuth()
</script>

<template>
  <div>
    <button v-if="!isAuthenticated" @click="login">
      Log in
    </button>
    
    <div v-else>
      <p>Welcome, {{ user?.given_name }}!</p>
      <button @click="logout">Log out</button>
    </div>
  </div>
</template>

Configuration

Full Configuration Options

export default defineNuxtConfig({
  kindeAuth: {
    // Required: Kinde domain
    authDomain: 'https://yourapp.kinde.com',
    
    // Required: Client credentials
    clientId: 'your_client_id',
    clientSecret: 'your_client_secret',
    
    // OAuth URLs
    redirectURL: '/api/kinde/callback',
    logoutRedirectURL: '/',
    postLoginRedirectURL: '/dashboard',
    
    // Cookie configuration
    cookie: {
      prefix: 'myapp_',    // Optional: Prefix for cookie names
      httpOnly: false,     // Allow client-side access for logout
      secure: true,        // HTTPS only in production
      sameSite: 'lax',     // CSRF protection
      path: '/',           // Cookie path
      maxAge: 604800       // 7 days in seconds
    },
    
    // Middleware configuration
    middleware: {
      enabled: true,                    // Enable route protection
      global: true,                     // Protect all routes by default
      publicRoutes: ['/', '/about']     // Routes that don't require auth
    },
    
    // Debug configuration
    debug: {
      enabled: false  // Enable debug endpoints in development only
    }
  }
})

Cookie Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | prefix | string | '' | Cookie name prefix to prevent conflicts between projects | | httpOnly | boolean | false | HttpOnly flag for cookies | | secure | boolean | true (prod) | Secure flag for cookies | | sameSite | 'lax' \| 'strict' \| 'none' | 'lax' | SameSite attribute | | path | string | '/' | Cookie path | | maxAge | number | 604800 | Max age in seconds (7 days) |

Note: The prefix option is useful when running multiple projects on localhost:3000. For example, setting prefix: 'project1_' will create cookies like project1_access_token instead of just access_token, preventing conflicts between different projects.

Middleware Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | enabled | boolean | true | Enable global middleware | | global | boolean | true | Make middleware global | | publicRoutes | string[] | ['/'] | Public routes (no auth required) |

Composable API

useKindeAuth()

The main composable for authentication functionality.

Returns

{
  // State
  isAuthenticated: Ref<boolean>
  user: Ref<KindeUser | null>
  isLoading: Ref<boolean>
  
  // Computed
  userDisplayName: Ref<string>
  userEmail: Ref<string | null>
  userPicture: Ref<string | null>
  
  // Methods
  login: () => Promise<void>
  logout: () => void
  checkAuth: () => boolean
  fetchUser: () => Promise<KindeUser | null>
  getToken: () => Promise<string | null>
  refreshToken: () => Promise<boolean>
}

User Type

interface KindeUser {
  id: string
  email?: string
  given_name?: string
  family_name?: string
  picture?: string
  [key: string]: unknown
}

API Endpoints

The module automatically registers these endpoints:

| Endpoint | Method | Description | |----------|--------|-------------| | /api/kinde/login | GET | Initiate OAuth login | | /api/kinde/logout | GET | Logout and clear session | | /api/kinde/callback | GET | OAuth callback handler | | /api/kinde/user | GET | Get current user info | | /api/kinde/token | GET | Get access token (auto-refreshes if expired) | | /api/kinde/refresh | GET | Manually refresh access token | | /api/kinde/debug/token | GET | Debug endpoint (dev only) |

Server-Side Usage

Access Kinde context in server routes:

// server/api/example.ts
export default defineEventHandler(async (event) => {
  const kindeClient = event.context.kinde
  
  // Check authentication
  const isAuthenticated = await kindeClient.isAuthenticated()
  
  if (!isAuthenticated) {
    throw createError({
      statusCode: 401,
      statusMessage: 'Unauthorized'
    })
  }
  
  // Get user
  const user = await kindeClient.getUser()
  
  // Get token
  const token = await kindeClient.getToken()
  
  // Get permissions
  const permissions = await kindeClient.getPermissions()
  
  // Get feature flags
  const hasFeature = await kindeClient.getBooleanFlag('new_feature', false)
  
  return { user, permissions, hasFeature }
})

Route Protection

Using Built-in Middleware

The module provides optional global middleware for route protection:

// nuxt.config.ts
export default defineNuxtConfig({
  kindeAuth: {
    middleware: {
      enabled: true,
      global: true,
      publicRoutes: [
        '/',
        '/about',
        '/blog'
      ]
    }
  }
})

Custom Middleware

You can also create custom middleware:

// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
  const { isAuthenticated, checkAuth } = useKindeAuth()
  
  checkAuth()
  
  if (!isAuthenticated.value && to.path.startsWith('/dashboard')) {
    return navigateTo('/api/kinde/login', { external: true })
  }
})

Advanced Usage

Cookie Prefix for Multiple Projects

When developing multiple Nuxt projects locally, they typically run on the same domain (localhost:3000), which can cause cookie conflicts. Use the cookie.prefix option to isolate sessions:

// Project 1: Habityzer
export default defineNuxtConfig({
  kindeAuth: {
    cookie: {
      prefix: 'habityzer_'
    }
  }
})

// Project 2: Dashboard
export default defineNuxtConfig({
  kindeAuth: {
    cookie: {
      prefix: 'dashboard_'
    }
  }
})

This creates separate cookies for each project:

  • Project 1: habityzer_access_token, habityzer_refresh_token, etc.
  • Project 2: dashboard_access_token, dashboard_refresh_token, etc.

Extending the Module

You can wrap useKindeAuth with your own composable to add custom functionality:

// composables/useAuth.ts
export const useAuth = () => {
  const kindeAuth = useKindeAuth()
  
  // Fetch additional user data from your API
  const fetchUserProfile = async () => {
    const response = await $fetch('/api/user/profile')
    return response
  }
  
  return {
    ...kindeAuth,
    fetchUserProfile
  }
}

Token Management & Auto-Refresh

The module automatically manages token refresh using the stored refresh token. When you call getToken(), it checks if the access token is expired or about to expire (within 5 minutes) and automatically refreshes it:

const { getToken, refreshToken } = useKindeAuth()

// Automatic refresh - the module handles expired tokens
const token = await getToken() // Refreshes automatically if needed

// Use token in API calls
const data = await $fetch('/api/protected-resource', {
  headers: {
    Authorization: `Bearer ${token}`
  }
})

// Manual refresh (optional)
const success = await refreshToken()
if (success) {
  console.log('Token refreshed successfully')
}

How it works:

  1. Access tokens are checked for expiry before being returned
  2. If expired or expiring soon (< 5 minutes), the refresh token is used automatically
  3. New tokens are saved to cookies seamlessly
  4. If refresh fails (expired refresh token), the user is logged out

Proxy Pattern for Backend API

Create a proxy to forward requests with Kinde tokens:

// server/api/backend/[...path].ts
export default defineEventHandler(async (event) => {
  const kindeClient = event.context.kinde
  const token = await kindeClient.getToken()
  
  const path = event.context.params?.path || ''
  const config = useRuntimeConfig()
  
  return $fetch(`${config.backendUrl}/${path}`, {
    headers: {
      Authorization: `Bearer ${token}`
    }
  })
})

Debug Mode

Enable debug endpoints and debug page in development:

// nuxt.config.ts
export default defineNuxtConfig({
  kindeAuth: {
    debug: {
      enabled: process.env.NODE_ENV !== 'production'
    }
  }
})

🛠️ Nuxt DevTools Integration

The module automatically adds a "Kinde Auth" tab to your Nuxt DevTools in development mode!

To use it:

  1. Open your Nuxt app in development mode
  2. Click the Nuxt icon (usually bottom-right corner, or press Shift + Alt/Option + D)
  3. Click the "Kinde Auth" tab in the DevTools sidebar

The DevTools tab displays:

  • Authentication Status - Live status indicator
  • Current User Info - See authenticated user details
  • Token Status - Real-time token expiry countdown with auto-refresh
  • Configuration - All your Kinde settings (cookie prefix, redirects, etc.)
  • Interactive Testing - Test token refresh, API calls, and more

No configuration needed! The tab appears automatically when debug.enabled is true.

🔍 Debug Page

When debug mode is enabled, the debug URL will be logged to your browser console on app startup.

Access the interactive debug page at:

http://localhost:3000/__kinde-debug

Quick Access: Bookmark this URL or check your browser console for the debug link!

The debug page provides:

  • Configuration Display - View all your Kinde settings (cookie prefix, redirects, etc.)
  • Real-time Token Status - Expiry countdown and status indicators
  • Interactive Token Refresh - Test manual and automatic refresh
  • API Call Testing - Verify tokens work with your endpoints
  • Token Inspection - Decode and view token contents
  • Auto-refresh - Updates every 10 seconds
  • User Information - Display current user details

Perfect for testing:

  • Token expiry and refresh functionality
  • API calls with authentication
  • Token lifecycle management
  • Troubleshooting auth issues
  • Verifying configuration settings

Debug API Endpoints

Token Information

GET /api/kinde/debug/token-info

Returns comprehensive token status:

{
  "authenticated": true,
  "tokens": {
    "access": {
      "isExpired": false,
      "isExpiringSoon": true,
      "expiresAt": "2024-01-01T12:00:00Z",
      "timeUntilExpiry": 245,
      "timeUntilExpiryFormatted": "4m 5s"
    },
    "refresh": {
      "exists": true
    }
  },
  "refreshStatus": {
    "canRefresh": true,
    "shouldRefresh": true,
    "reason": "Token expires in less than 5 minutes"
  }
}

Raw Tokens

GET /api/kinde/debug/token

Returns decoded tokens:

{
  "accessToken": {
    "raw": "eyJ...",
    "decoded": { ... }
  },
  "idToken": {
    "raw": "eyJ...",
    "decoded": { ... }
  }
}

TypeScript Support

The module includes full TypeScript support:

import type { KindeUser } from '@habityzer/nuxt-kinde-auth'

const user: KindeUser = {
  id: '123',
  email: '[email protected]',
  given_name: 'John',
  family_name: 'Doe'
}

Migration Guide

From Custom Kinde Integration

If you have an existing Kinde integration:

  1. Install the module

    pnpm add @habityzer/nuxt-kinde-auth
  2. Update nuxt.config.ts

    • Add module to modules array
    • Move Kinde config to kindeAuth key
    • Remove manual runtime config
  3. Remove old files

    • Delete server/middleware/kinde.ts
    • Delete server/api/login.get.ts
    • Delete server/api/logout.get.ts
    • Delete server/api/callback.get.ts
  4. Update imports

    • Replace custom useAuth with useKindeAuth
    • Update API endpoint URLs (/api/login/api/kinde/login)
  5. Test thoroughly

    • Verify login/logout works
    • Check route protection
    • Test server-side auth

Troubleshooting

"Kinde authentication not initialized"

Cause: Module not loaded or configuration missing.

Solution:

  • Ensure @habityzer/nuxt-kinde-auth is in your modules array
  • Verify authDomain, clientId, and clientSecret are set
  • Restart dev server

Session Not Persisting

Cause: Cookie configuration issues.

Solution:

  • Check cookie.secure setting (should be false for localhost)
  • Verify cookie.sameSite is set to 'lax'
  • Clear browser cookies and try again

Redirect Loop on Login

Cause: Middleware configuration conflict.

Solution:

  • Ensure /api/kinde/callback is in publicRoutes
  • Check that middleware is not blocking auth endpoints
  • Disable module middleware if using custom middleware

Token Refresh Issues

Cause: Refresh token expired or invalid.

Solution:

  • Refresh tokens have a longer lifespan but do expire eventually
  • If refresh fails, users must re-authenticate
  • Check Kinde dashboard for token expiry settings
  • The module automatically handles this by clearing session and requiring login

Requirements

  • Nuxt 4.x
  • Node.js >= 18
  • Kinde account and application

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues and questions:


Made with ❤️ for the Nuxt community