@habityzer/nuxt-symfony-kinde-layer 2.4.0 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.4.2](https://github.com/Habityzer/nuxt-symfony-kinde-layer/compare/v2.4.1...v2.4.2) (2026-03-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Remove unused @nuxt/image dependency ([631f4f6](https://github.com/Habityzer/nuxt-symfony-kinde-layer/commit/631f4f601e8dbb5753d06adc5471f7a54632a636))
7
+
8
+ ## [2.4.1](https://github.com/Habityzer/nuxt-symfony-kinde-layer/compare/v2.4.0...v2.4.1) (2026-03-17)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * Improve logging in Symfony proxy and auth guard middleware ([4613f74](https://github.com/Habityzer/nuxt-symfony-kinde-layer/commit/4613f74fc9d9d6a4ed796675367176d46f1e0a7e))
14
+
1
15
  # [2.4.0](https://github.com/Habityzer/nuxt-symfony-kinde-layer/compare/v2.3.0...v2.4.0) (2026-03-16)
2
16
 
3
17
 
package/README.md CHANGED
@@ -224,6 +224,22 @@ kindeAuth: {
224
224
  }
225
225
  ```
226
226
 
227
+ ### Disabling layer modules
228
+
229
+ You can disable individual modules provided by the layer by setting them to `false` in your project's `nuxt.config.ts`. The layer is still used via `extends`; only the module is disabled. For example, if you do not use `@nuxt/image`:
230
+
231
+ ```typescript
232
+ export default defineNuxtConfig({
233
+ extends: ['@habityzer/nuxt-symfony-kinde-layer'],
234
+ image: false,
235
+ // ...
236
+ })
237
+ ```
238
+
239
+ ### Route groups (optional)
240
+
241
+ As an alternative to listing only public routes, you can use Nuxt route groups (e.g. `(protected)/dashboard`) and check `to.meta.groups` in middleware. For example, put protected pages under `pages/(protected)/` and in a custom middleware use `if (to.meta.groups?.includes('protected') && !isAuthenticated()) return navigateTo('/login')`. The layer's auth guard uses `publicRoutes` / `protectedRoutes` by default; route groups are optional for projects that prefer convention-based protection.
242
+
227
243
  ## E2E Testing
228
244
 
229
245
  The layer supports E2E testing with app tokens:
@@ -353,6 +369,10 @@ Add these to your workflow:
353
369
 
354
370
  ## Troubleshooting
355
371
 
372
+ ### Error handling and Nuxt 5 readiness
373
+
374
+ The layer uses Nuxt 4.4+ / Nuxt 5 style errors: `createError({ status, statusText })` instead of the deprecated `statusCode`/`statusMessage`. When handling errors from the proxy or auth composable, prefer reading `error.status` and `error.statusText`. The deprecated `statusCode` and `statusMessage` remain supported on `NuxtError` for backward compatibility during migration.
375
+
356
376
  ### Cookie Name Conflicts
357
377
 
358
378
  If you see authentication issues, ensure each project has a unique cookie prefix:
@@ -90,8 +90,9 @@ export const useAuth = () => {
90
90
  userProfile.value = response
91
91
  return response
92
92
  } catch (error) {
93
- // Silently handle auth errors on public pages
94
- if (error && typeof error === 'object' && 'statusCode' in error && error.statusCode === 401) {
93
+ // Silently handle auth errors on public pages (support both status and statusCode for Nuxt 4.4+ / 5)
94
+ const err = error as { status?: number, statusCode?: number } | undefined
95
+ if (err && typeof err === 'object' && (err.status === 401 || err.statusCode === 401)) {
95
96
  console.debug('Auth check failed - user not logged in')
96
97
  } else {
97
98
  console.error('Failed to fetch user profile:', error)
@@ -12,9 +12,10 @@ export default defineNuxtPlugin(() => {
12
12
  const e2eTokenCookieName = requireString(middlewareConfig.e2eTokenCookieName, 'kindeAuth.middleware.e2eTokenCookieName')
13
13
  const appTokenPrefix = requireString(middlewareConfig.appTokenPrefix, 'kindeAuth.middleware.appTokenPrefix')
14
14
  const clockSkewSeconds = requireNonNegativeNumber(middlewareConfig.clockSkewSeconds, 'kindeAuth.middleware.clockSkewSeconds')
15
- const idToken = useCookie<string | null>(`${cookiePrefix}${idTokenBaseName}`)
16
- const accessToken = useCookie<string | null>(`${cookiePrefix}${accessTokenBaseName}`)
17
- const e2eToken = useCookie<string | null>(`${cookiePrefix}${e2eTokenCookieName}`)
15
+ const cookieOptions = { maxAge: 60 * 60 * 24 * 7, refresh: true }
16
+ const idToken = useCookie<string | null>(`${cookiePrefix}${idTokenBaseName}`, cookieOptions)
17
+ const accessToken = useCookie<string | null>(`${cookiePrefix}${accessTokenBaseName}`, cookieOptions)
18
+ const e2eToken = useCookie<string | null>(`${cookiePrefix}${e2eTokenCookieName}`, cookieOptions)
18
19
  const mode = middlewareConfig.mode || 'privateByDefault'
19
20
  const publicRoutes: string[] = middlewareConfig.publicRoutes || ['/']
20
21
  const protectedRoutes: string[] = middlewareConfig.protectedRoutes || []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@habityzer/nuxt-symfony-kinde-layer",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "Shared Nuxt layer for Symfony + Kinde authentication integration",
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -25,7 +25,6 @@
25
25
  "dependencies": {
26
26
  "@habityzer/nuxt-kinde-auth": "^1.2.2",
27
27
  "@nuxt/eslint": "^1.9.0",
28
- "@nuxt/image": "^1.11.0",
29
28
  "@nuxt/ui": "^4.0.1",
30
29
  "@pinia/nuxt": "^0.11.2",
31
30
  "@vueuse/core": "^13.9.0",
@@ -47,7 +47,9 @@ export default defineEventHandler(async (event) => {
47
47
 
48
48
  // Skip authentication for public routes
49
49
  if (isPublicRoute) {
50
- console.log('🔓 [SYMFONY PROXY] Public route, skipping auth:', path)
50
+ if (!process.env.E2E_TEST_MODE) {
51
+ console.log('[SYMFONY PROXY]', event.method, path, '(public)')
52
+ }
51
53
  // Set token to empty to skip auth headers
52
54
  token = ''
53
55
  } else {
@@ -65,8 +67,8 @@ export default defineEventHandler(async (event) => {
65
67
 
66
68
  if (!kinde?.client || !kinde?.sessionManager) {
67
69
  throw createError({
68
- statusCode: 500,
69
- statusMessage:
70
+ status: 500,
71
+ statusText:
70
72
  'Kinde authentication not initialized. Module may not be loaded correctly.'
71
73
  })
72
74
  }
@@ -97,15 +99,15 @@ export default defineEventHandler(async (event) => {
97
99
 
98
100
  if (!token || token.trim() === '') {
99
101
  throw createError({
100
- statusCode: 401,
101
- statusMessage: 'Unauthorized - Please log in'
102
+ status: 401,
103
+ statusText: 'Unauthorized - Please log in'
102
104
  })
103
105
  }
104
106
  } catch (error) {
105
107
  console.error('❌ [SYMFONY PROXY] Auth error:', error)
106
108
  throw createError({
107
- statusCode: 401,
108
- statusMessage:
109
+ status: 401,
110
+ statusText:
109
111
  error instanceof Error ? error.message : 'Authentication failed'
110
112
  })
111
113
  }
@@ -114,8 +116,8 @@ export default defineEventHandler(async (event) => {
114
116
 
115
117
  if (!token && !isPublicRoute) {
116
118
  throw createError({
117
- statusCode: 401,
118
- statusMessage: 'No authentication token available'
119
+ status: 401,
120
+ statusText: 'No authentication token available'
119
121
  })
120
122
  }
121
123
 
@@ -162,19 +164,10 @@ export default defineEventHandler(async (event) => {
162
164
  headers['Accept'] = accept
163
165
  }
164
166
 
165
- // Log the request to backend
166
- const backendUrl = `${config.apiBaseUrl}${path}`
167
- console.log('🔵 [SYMFONY PROXY] Request to backend:', {
168
- url: backendUrl,
169
- method,
170
- headers: {
171
- ...headers,
172
- Authorization: token && token !== '' ? `Bearer kinde_${token.substring(0, 10)}...` : 'none'
173
- },
174
- query,
175
- hasBody: !!body,
176
- isMultipart: contentType.includes('multipart/form-data')
177
- })
167
+ // Log one short line per request (method + path only); skip in e2e to reduce output
168
+ if (!process.env.E2E_TEST_MODE) {
169
+ console.log('[SYMFONY PROXY]', method, path)
170
+ }
178
171
 
179
172
  // Forward request to Symfony with Kinde token
180
173
  const response = await $fetch(path, {
@@ -187,41 +180,30 @@ export default defineEventHandler(async (event) => {
187
180
  timeout: 30000 // 30 second timeout
188
181
  })
189
182
 
190
- console.log('✅ [SYMFONY PROXY] Backend response received:', {
191
- url: backendUrl,
192
- method,
193
- status: 'success'
194
- })
195
-
196
183
  return response
197
184
  } catch (error) {
198
- console.error('❌ [SYMFONY PROXY] Symfony API error:', {
199
- path,
200
- statusCode:
201
- error && typeof error === 'object' && 'statusCode' in error
202
- ? error.statusCode
203
- : 'unknown',
204
- message: error instanceof Error ? error.message : 'unknown'
205
- })
206
- // Handle Symfony API errors
207
- const statusCode
208
- = error && typeof error === 'object' && 'statusCode' in error
209
- ? (error.statusCode as number)
185
+ const err = error as Record<string, unknown> | undefined
186
+ const status
187
+ = err && typeof err === 'object' && ('status' in err || 'statusCode' in err)
188
+ ? (err.status as number) ?? (err.statusCode as number)
210
189
  : 500
211
- const statusMessage
212
- = error && typeof error === 'object' && 'statusMessage' in error
213
- ? (error.statusMessage as string)
190
+ const statusText
191
+ = err && typeof err === 'object' && ('statusText' in err || 'statusMessage' in err)
192
+ ? (err.statusText as string) ?? (err.statusMessage as string)
214
193
  : error instanceof Error
215
194
  ? error.message
216
195
  : 'Symfony API error'
196
+ console.error('❌ [SYMFONY PROXY] Symfony API error:', {
197
+ path,
198
+ status,
199
+ message: statusText
200
+ })
217
201
  const data
218
- = error && typeof error === 'object' && 'data' in error
219
- ? error.data
220
- : undefined
202
+ = err && typeof err === 'object' && 'data' in err ? err.data : undefined
221
203
 
222
204
  throw createError({
223
- statusCode,
224
- statusMessage,
205
+ status,
206
+ statusText,
225
207
  data
226
208
  })
227
209
  }
@@ -127,6 +127,10 @@ function logServer(event: string, details: Record<string, unknown>) {
127
127
  if (process.env.NODE_ENV === 'production') {
128
128
  return
129
129
  }
130
+ // Only log when explicitly enabled (reduces noise in e2e and dev)
131
+ if (!process.env.NUXT_AUTH_GUARD_DEBUG) {
132
+ return
133
+ }
130
134
 
131
135
  console.warn(`[AUTH GUARD SERVER] ${event}`, details)
132
136
  }