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-symfony-kinde-layer

v2.3.0

Published

Shared Nuxt layer for Symfony + Kinde authentication integration

Downloads

434

Readme

@habityzer/nuxt-symfony-kinde-layer

Shared Nuxt layer for Symfony + Kinde authentication integration. This layer provides common authentication logic, API proxying, and pre-configured modules for Nuxt projects using Symfony backends with Kinde authentication.

Features

  • Symfony API Proxy - Automatically forwards requests with Kinde auth tokens
  • Accept Header Fix - Properly forwards Accept header for content negotiation (JSON vs Hydra)
  • Auth Composable - Unified authentication state management
  • Global Auth Middleware - Configurable route protection
  • E2E Testing Support - Built-in support for automated testing
  • Pre-configured Modules - Includes @nuxt/ui, @nuxt/image, Pinia, ESLint, and more
  • Type-safe - Full TypeScript support with OpenAPI integration

Installation

Using pnpm workspace (recommended for monorepos)

# In your project root
pnpm add @habityzer/nuxt-symfony-kinde-layer

Or link locally

cd /path/to/@habityzer/nuxt-symfony-kinde-layer
pnpm install
pnpm link --global

cd /path/to/your-project
pnpm link --global @habityzer/nuxt-symfony-kinde-layer

Usage

1. Extend the layer in your nuxt.config.ts

export default defineNuxtConfig({
  extends: ['@habityzer/nuxt-symfony-kinde-layer'],

  // Runtime config - expose auth settings for middleware
  runtimeConfig: {
    apiBaseUrl: process.env.API_BASE_URL,
    
    public: {
      apiBaseUrl: process.env.API_BASE_URL,
      
      // Optional: Override layer defaults for auth config
      kindeAuth: {
        cookie: {
          prefix: 'myapp_' // Override default cookie prefix
        },
        middleware: {
          publicRoutes: ['/', '/blog', '/help'] // Override default public routes
        }
      }
    }
  },

  // Configure Kinde authentication module
  kindeAuth: {
    authDomain: process.env.KINDE_AUTH_DOMAIN,
    clientId: process.env.KINDE_CLIENT_ID,
    clientSecret: process.env.KINDE_CLIENT_SECRET,
    redirectURL: process.env.KINDE_REDIRECT_URL,
    logoutRedirectURL: process.env.KINDE_LOGOUT_REDIRECT_URL,
    postLoginRedirectURL: '/dashboard',
    cookie: {
      prefix: 'myapp_' // IMPORTANT: Must match runtimeConfig.public.kindeAuth.cookie.prefix
    },
    middleware: {
      publicRoutes: ['/', '/blog', '/help'] // Must match runtimeConfig.public
    }
  }
})

2. Environment Variables

Create a .env file in your project:

# Symfony Backend
API_BASE_URL=http://localhost:8000

# Kinde Authentication (required by @habityzer/nuxt-kinde-auth module)
KINDE_AUTH_DOMAIN=https://your-domain.kinde.com
KINDE_CLIENT_ID=your-client-id
KINDE_CLIENT_SECRET=your-client-secret
KINDE_REDIRECT_URL=http://localhost:3000/api/kinde/callback
KINDE_LOGOUT_REDIRECT_URL=http://localhost:3000

# Layer Configuration (optional - layer provides defaults)
NUXT_PUBLIC_AUTH_COOKIE_PREFIX=myapp_
NUXT_PUBLIC_AUTH_LOGIN_PATH=/api/kinde/login
NUXT_PUBLIC_AUTH_CLOCK_SKEW_SECONDS=300
NUXT_PUBLIC_AUTH_APP_TOKEN_PREFIX=Bearer
NUXT_PUBLIC_AUTH_E2E_TOKEN_COOKIE_NAME=kinde_token
NUXT_PUBLIC_AUTH_ID_TOKEN_NAME=id_token
NUXT_PUBLIC_AUTH_ACCESS_TOKEN_NAME=access_token
NUXT_PUBLIC_AUTH_REFRESH_TOKEN_NAME=refresh_token

Note: The layer provides sensible defaults for all NUXT_PUBLIC_AUTH_* variables. You only need to override them if you want different values. The KINDE_* variables are required.

3. Use the Auth Composable

<script setup lang="ts">
const {
  isAuthenticated,
  currentUser,
  userDisplayName,
  userEmail,
  isPremium,
  login,
  logout,
  fetchUserProfile
} = useAuth()

// Fetch user profile on mount
onMounted(async () => {
  if (isAuthenticated.value) {
    await fetchUserProfile()
  }
})
</script>

<template>
  <div>
    <template v-if="isAuthenticated">
      <p>Welcome, {{ userDisplayName }}!</p>
      <p v-if="isPremium">Premium user</p>
      <button @click="logout">Logout</button>
    </template>
    <template v-else>
      <button @click="login">Login</button>
    </template>
  </div>
</template>

4. Call Symfony APIs

The layer automatically proxies requests to /api/symfony/*:

// This calls your Symfony backend at /api/users
const users = await $fetch('/api/symfony/api/users')

// With generated OpenAPI composables
const { getUsersApi } = useUsersApi()
const response = await getUsersApi()

What's Included

Modules

  • @nuxt/ui - UI component library
  • @nuxt/image - Image optimization
  • @nuxt/eslint - Linting
  • @pinia/nuxt - State management
  • @habityzer/nuxt-kinde-auth - Kinde authentication
  • @vueuse/core - Vue composition utilities

Files

  • server/api/symfony/[...].ts - Symfony API proxy with auth
  • server/middleware/auth-guard.ts - Server-side authentication middleware
  • server/utils/auth-constants.ts - Re-exports shared auth constants for server
  • app/composables/useAuth.ts - Authentication composable
  • app/plugins/auth-guard.client.ts - Client-side authentication guard
  • app/constants/auth.ts - Re-exports shared auth constants for app
  • shared/auth-constants.ts - Core authentication constants (source of truth)

Configuration Options

Cookie Prefix

CRITICAL: Always set a unique cookie prefix per project to avoid cookie conflicts when running multiple projects locally:

// MUST be set in BOTH places:
runtimeConfig: {
  public: {
    kindeAuth: {
      cookie: {
        prefix: 'myproject_' // For middleware to read
      }
    }
  }
},

kindeAuth: {
  cookie: {
    prefix: 'myproject_' // For Kinde module (must match above)
  }
}

Why both?

  • kindeAuth.cookie.prefix - Used by the Kinde auth module to set/read cookies
  • runtimeConfig.public.kindeAuth.cookie.prefix - Used by the layer's middleware to check authentication

Without unique prefixes: If you run ew-nuxt and habityzer-nuxt locally at the same time, they'll share cookies and cause auth conflicts!

Public Routes

Configure which routes don't require authentication:

kindeAuth: {
  middleware: {
    publicRoutes: [
      '/',
      '/blog',
      '/about',
      '/legal'
    ]
  }
}

E2E Testing

The layer supports E2E testing with app tokens:

  1. Generate an app token in Symfony:

    php bin/console app:token:manage create
  2. Set the token in your E2E tests:

    // Set cookie
    await page.context().addCookies([{
      name: 'kinde_token',
      value: 'app_your_token_here',
      domain: 'localhost',
      path: '/'
    }])

API Schema Generation

The layer includes OpenAPI tools for generating typed API composables:

# Generate TypeScript types from OpenAPI schema
pnpm generate:types

# Generate API composables
pnpm generate:api

# Or do both
pnpm sync:api

Add these scripts to your project's package.json:

{
  "scripts": {
    "generate:types": "openapi-typescript ./schema/api.json -o ./app/types/api.ts --default-non-nullable false && eslint ./app/types/api.ts --fix",
    "generate:api": "pnpm generate:types && nuxt-openapi-composables generate -s ./schema/api.json -o ./app/composables/api --types-import '~/types/api'",
    "sync:api": "pnpm update:schema && pnpm generate:api"
  }
}

Development

Local Development Setup

  1. Install dependencies:

    pnpm install
  2. Available scripts:

    pnpm dev          # Run dev server with example env
    pnpm build        # Build the layer
    pnpm lint         # Check for linting issues
    pnpm lint:fix     # Auto-fix linting issues
    pnpm release      # Create semantic release (CI only)
  3. Git hooks (via Husky):

    • Pre-commit: Automatically runs pnpm lint before each commit
    • Commit-msg: Validates commit message format (conventional commits)
  4. First time setup: The pre-commit hook will automatically run nuxt prepare if needed (with placeholder environment variables).

Commit Message Format

This project uses Conventional Commits. Your commits must follow this format:

type(scope): subject

body (optional)

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • style: Code style changes (formatting, etc.)
  • refactor: Code refactoring
  • test: Adding or updating tests
  • chore: Maintenance tasks

Examples:

git commit -m "feat: add authentication middleware"
git commit -m "fix: resolve cookie prefix conflict"
git commit -m "docs: update README with CI setup"

CI/CD Setup

Required Environment Variables for GitHub Actions

When building or publishing this layer in CI/CD (e.g., GitHub Actions), you need to provide placeholder environment variables for the nuxt prepare step. The layer's nuxt.config.ts validates these at build time.

Add these to your workflow:

- name: Prepare Nuxt
  env:
    KINDE_AUTH_DOMAIN: https://placeholder.kinde.com
    KINDE_CLIENT_ID: placeholder_client_id
    KINDE_CLIENT_SECRET: placeholder_client_secret
    KINDE_REDIRECT_URL: http://localhost:3000/api/auth/callback
    KINDE_LOGOUT_REDIRECT_URL: http://localhost:3000
    NUXT_PUBLIC_AUTH_COOKIE_PREFIX: auth_
    NUXT_PUBLIC_AUTH_LOGIN_PATH: /login
    NUXT_PUBLIC_AUTH_CLOCK_SKEW_SECONDS: 300
    NUXT_PUBLIC_AUTH_APP_TOKEN_PREFIX: Bearer
    NUXT_PUBLIC_AUTH_E2E_TOKEN_COOKIE_NAME: e2e_token
    NUXT_PUBLIC_AUTH_ID_TOKEN_NAME: id_token
    NUXT_PUBLIC_AUTH_ACCESS_TOKEN_NAME: access_token
    NUXT_PUBLIC_AUTH_REFRESH_TOKEN_NAME: refresh_token
  run: pnpm nuxt prepare

Note: These are placeholder values only used for type generation and validation. Projects consuming this layer will provide their own real credentials at runtime.

Troubleshooting

Cookie Name Conflicts

If you see authentication issues, ensure each project has a unique cookie prefix:

// Project A
kindeAuth: { cookie: { prefix: 'projecta_' } }

// Project B  
kindeAuth: { cookie: { prefix: 'projectb_' } }

TypeScript Errors with API Responses

If you get type mismatches between expected Hydra collections and plain arrays, the proxy is correctly forwarding the Accept header. Make sure your OpenAPI schema matches what the API actually returns.

Architecture & Design Decisions

Shared Constants Architecture

The layer uses a centralized constants file at shared/auth-constants.ts as the single source of truth for authentication configuration values (cookie names, token prefixes, etc.).

Structure:

  • shared/auth-constants.ts - Core constants definitions
  • app/constants/auth.ts - Re-exports for client-side code (supports ~/constants/auth imports)
  • server/utils/auth-constants.ts - Re-exports for server-side code (supports #imports and relative imports)

Why this structure:

  • Single source of truth prevents drift between client and server values
  • Re-export pattern works around Nuxt/Nitro bundling constraints
  • Maintains clean import paths for consuming projects

Runtime Configuration

The layer uses Nuxt's runtimeConfig to make authentication settings available to both server middleware and client code:

Implementation:

  1. Constants are imported in nuxt.config.ts from shared/auth-constants.ts
  2. Environment variables override defaults (e.g., NUXT_PUBLIC_AUTH_COOKIE_PREFIX)
  3. Values are merged into runtimeConfig.public.kindeAuth for runtime access
  4. Both server middleware and client plugins read from runtime config

This approach allows:

  • Projects to override defaults via environment variables
  • Type-safe access to configuration throughout the app
  • Consistent behavior between development and production

Cookie Prefix Configuration

The layer uses a project-specific cookie prefix (e.g., ew-, habityzer_) to prevent cookie conflicts when running multiple projects locally.

Implementation:

  1. Base cookie names are defined without prefixes (id_token, access_token)
  2. Projects configure their prefix in nuxt.config.ts
  3. The prefix is applied dynamically at runtime by middleware and composables
  4. Projects should NOT redefine the cookie constant names - they inherit from the layer

TypeScript Type Suppressions

You may see @ts-expect-error comments for the cookie property in configuration files. This is expected and safe.

Reason: The @habityzer/nuxt-kinde-auth module's TypeScript definitions don't include our custom cookie.prefix configuration property, but it works correctly at runtime.

Solution: We use @ts-expect-error comments to suppress TypeScript errors without compromising type safety elsewhere in the codebase.

Cache Clearing

If you encounter auto-import issues after updating the layer (especially for composables), clear your Nuxt cache:

rm -rf .nuxt node_modules/.cache
pnpm build

This forces Nuxt to regenerate its auto-import registry and pick up changes from the layer.

License

MIT

Contributing

This is a private layer for Habityzer projects. For issues or improvements, contact the team.