@devcoffee/nuxt-core 1.4.0 → 1.4.1

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,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.4.1
4
+
5
+ [compare changes](https://github.com/coolkg1412/devcoffee-nuxt-core/compare/v1.4.0...v1.4.1)
6
+
7
+ ### 🩹 Fixes
8
+
9
+ - Normalize expiresIn to seconds across all session consumers ([2c197ab](https://github.com/coolkg1412/devcoffee-nuxt-core/commit/2c197ab))
10
+
11
+ ### ❤️ Contributors
12
+
13
+ - Hieu Nguyen <hieu.nguyen@devcoffee.tech>
14
+
3
15
  ## v1.4.0
4
16
 
5
17
  [compare changes](https://github.com/coolkg1412/devcoffee-nuxt-core/compare/v1.3.0...v1.4.0)
package/dist/module.d.mts CHANGED
@@ -3,249 +3,255 @@ import { CookieSerializeOptions } from '../dist/runtime/server/adapters/http.js'
3
3
  import { OidcUserInfo } from '../dist/runtime/server/adapters/oidc.js';
4
4
  import { LogLevel as LogLevel$1, ConsolaOptions, ConsolaInstance } from 'consola';
5
5
 
6
- interface AuthorizedUser {
7
- id: string
8
- sub: string
9
- email: string
10
- firstName: string
11
- lastName: string
12
- locale: string
13
- language: string
14
- timezone: string
15
- }
16
-
17
- type AuthStatus = 'unauthenticated' | 'authenticated'
18
-
19
- type AuthData = {
20
- status: AuthStatus
21
- tokenSet?: {
22
- accessToken: string
23
- tokenType: string
24
- expiresAt: number
25
- idToken: string
26
- refreshToken: string
27
- scopes: string[]
28
- }
29
- }
30
-
31
- type SessionContext<TData = Record<string, unknown>> = {
32
- id: string
33
- auth: AuthData
34
- user: AuthorizedUser
35
- data: TData
36
- issuedAt: number
37
- expiresAt: number
38
- }
39
-
40
- type NuxtAuthOptions = {
41
- /**
42
- * Default Devcoffee Nuxt AuthTS option callbacks for session and user mapping.
43
- * These can be overridden by passing custom callbacks to `NuxtAuthtsHandler()`.
44
- * @since 1.0.0
45
- */
46
- session: (
47
- session: Omit<SessionContext, 'auth'>,
48
- auth: SessionContext['auth']
49
- ) => Awaitable<Omit<SessionContext, 'auth' | 'issuedAt' | 'expiresAt'> & { isAuthenticated: boolean }>
50
-
51
- /**
52
- * Maps the OpenID Connect user info response to your local user schema.
53
- *
54
- * @param user - The raw user info response from the OpenID provider.
55
- * @param opts - The token response containing access and ID tokens.
56
- * @returns A normalized user object.
57
- * @since 1.0.0
58
- */
59
- userInfo: (
60
- user: AuthorizedUser,
61
- opts: {
62
- openidUser?: OidcUserInfo
63
- tokenSet: Exclude<SessionContext['auth']['tokenSet'], undefined>
64
- }
65
- ) => Awaitable<AuthorizedUser>
66
- }
67
-
68
- type NuxtSessionContext<TData = Record<string, unknown>> = {
69
- readonly id: string
70
- readonly isAuthenticated: boolean
71
- readonly user: AuthorizedUser
72
- readonly data: TData
73
- }
74
-
75
- type NuxtSessionUpdateContext<TData = Record<string, unknown>> = DeepPartial<{
76
- user: AuthorizedUser
77
- data: TData
78
- }>
79
-
80
- /**
81
- * ⚙️ OpenID Connect configuration options.
82
- *
83
- * Defines parameters used for client registration, discovery,
84
- * and token exchange with the OpenID Provider.
85
- *
86
- * @since 1.0.0
87
- */
88
- type OpenIdOptions = {
89
- /** Client ID registered with the OpenID Provider. */
90
- clientId: string
91
-
92
- /** Client secret for token exchange (if applicable). */
93
- clientSecret: string
94
-
95
- /** Whether to use Proof Key for Code Exchange (PKCE) flow. */
96
- usePkce: boolean
97
-
98
- /** Code challenge method, e.g. `S256`. */
99
- codeChallengeMethod: string
100
-
101
- /** Scopes requested from the OpenID Provider. */
102
- scopes: string[]
103
-
104
- /** Redirect URI used after authorization. */
105
- redirectUri: string
106
-
107
- /** The `.well-known/openid-configuration` discovery URL. */
108
- wellKnownUrl: string
109
-
110
- /** Whether to automatically fetch user info after login. */
111
- autoFetchUser: boolean
112
-
113
- /**
114
- * TTL in seconds for caching autoFetchUser results per session.
115
- * A GET_SESSION within the TTL window does not trigger an OIDC provider call.
116
- * Only applies when autoFetchUser is true.
117
- * @default 300
118
- * @since 1.0.0
119
- */
120
- autoFetchUserTtl: number
121
-
122
- /** Whether to fetch user info immediately after token grant. */
123
- fetchUserOnLogin: boolean
124
-
125
- /**
126
- * Window in milliseconds before token expiry at which a refresh is triggered.
127
- * Tokens with expiresAt more than this many milliseconds in the future are
128
- * considered fresh and the refresh path is skipped entirely.
129
- * @default 60000
130
- * @since 1.0.0
131
- */
132
- tokenRefreshBufferMs: number
133
-
134
- /**
135
- * When `true`, the token refresh mutex uses an atomic Redis NX write
136
- * (`SET key value NX EX ttl`) via the IORedis native client accessor for
137
- * true distributed exclusion across multiple server instances. When `false`
138
- * (default), the existing optimistic lock (`hasItem` + `setItem`) is used.
139
- *
140
- * @remarks Only effective when the Nitro `cache` storage mount is backed by
141
- * a Redis driver. Setting `true` with a non-Redis backend falls through to
142
- * the optimistic path silently.
143
- *
144
- * @default false
145
- * @since 1.0.0
146
- */
147
- distributedLock?: boolean
148
-
149
- /** Cache configuration for storing OpenID metadata. */
150
- cache: {
151
- /** Cache key prefix for the metadata store. */
152
- prefix: string
153
- /** Expiry time in seconds for cached metadata. */
154
- expires: number
155
- }
156
- }
157
-
158
- /**
159
- * 🍪 Session management configuration.
160
- *
161
- * Defines session storage, expiration, and cookie behavior
162
- * for authentication session tracking.
163
- *
164
- * @since 1.0.0
165
- */
166
- type SessionsOptions = {
167
- /** Cookie name mappings used by the session handler. */
168
- names: {
169
- /** PKCE verifier cookie name. */
170
- pkce: string
171
- /** State cookie name. */
172
- state: string
173
- /** Session ID cookie name. */
174
- sessionId: string
175
- /** Redirect URL cookie name. */
176
- redirectUrl: string
177
- }
178
-
179
- storage: {
180
- name: string
181
-
182
- /** Key prefix for session data in the storage backend. */
183
- prefix: string
184
- }
185
-
186
- /** Session lifetime in seconds. */
187
- expiresIn: number
188
-
189
- /** Options for how session cookies are serialized. */
190
- cookieOpts: CookieSerializeOptions
191
-
192
- /**
193
- * Secret used to HMAC-sign session ID cookies and derive the AES-256-GCM key
194
- * for tokenSet encryption. When empty, signing and encryption are skipped.
195
- * @since 1.0.0
196
- */
197
- secret?: string
198
- }
199
-
200
- /**
201
- * 🔐 Authentication behavior configuration.
202
- *
203
- * Defines default redirect paths and URIs used for login/logout flow.
204
- *
205
- * @since 1.0.0
206
- */
207
- type AuthOptions = {
208
- /** Path to the login page. */
209
- loginUri: string
210
-
211
- /** Default redirect URI after successful login. */
212
- defaultLoginRedirectUri: string
213
-
214
- /** Default redirect URI after logout. */
215
- defaultLogoutRedirectUri: string
216
-
217
- /** Default anonymous user object. */
218
- anonymousUser: AuthorizedUser
219
-
220
- ignoreRegexPatterns: RegExp[]
221
-
222
- ignoreRegexPatternsDev: RegExp[]
223
- }
224
-
225
- /**
226
- * 🧩 Main configuration interface for the Nuxt AuthTS module.
227
- *
228
- * Combines OpenID Connect, session, and general authentication options.
229
- *
230
- * @since 1.0.0
231
- */
232
- type AuthtsModuleOptions = {
233
- /** Enable or disable the module */
234
- enabled: boolean
235
- openid: OpenIdOptions
236
- sessions: SessionsOptions
237
- auth: AuthOptions
238
- }
239
-
240
- interface AuthtsMiddlewareMeta {
241
- /** Require authentication to access */
242
- required?: boolean
243
-
244
- /** Only accessible if unauthenticated (login/register pages) */
245
- unauthenticatedOnly?: boolean
246
-
247
- /** Restrict access to these roles */
248
- roles?: string[]
6
+ interface AuthorizedUser {
7
+ id: string
8
+ sub: string
9
+ email: string
10
+ firstName: string
11
+ lastName: string
12
+ locale: string
13
+ language: string
14
+ timezone: string
15
+ }
16
+
17
+ type AuthStatus = 'unauthenticated' | 'authenticated'
18
+
19
+ type AuthData = {
20
+ status: AuthStatus
21
+ tokenSet?: {
22
+ accessToken: string
23
+ tokenType: string
24
+ expiresAt: number
25
+ idToken: string
26
+ refreshToken: string
27
+ scopes: string[]
28
+ }
29
+ }
30
+
31
+ type SessionContext<TData = Record<string, unknown>> = {
32
+ id: string
33
+ auth: AuthData
34
+ user: AuthorizedUser
35
+ data: TData
36
+ issuedAt: number
37
+ expiresAt: number
38
+ }
39
+
40
+ type NuxtAuthOptions = {
41
+ /**
42
+ * Default Devcoffee Nuxt AuthTS option callbacks for session and user mapping.
43
+ * These can be overridden by passing custom callbacks to `NuxtAuthtsHandler()`.
44
+ * @since 1.0.0
45
+ */
46
+ session: (
47
+ session: Omit<SessionContext, 'auth'>,
48
+ auth: SessionContext['auth']
49
+ ) => Awaitable<Omit<SessionContext, 'auth' | 'issuedAt' | 'expiresAt'> & { isAuthenticated: boolean }>
50
+
51
+ /**
52
+ * Maps the OpenID Connect user info response to your local user schema.
53
+ *
54
+ * @param user - The raw user info response from the OpenID provider.
55
+ * @param opts - The token response containing access and ID tokens.
56
+ * @returns A normalized user object.
57
+ * @since 1.0.0
58
+ */
59
+ userInfo: (
60
+ user: AuthorizedUser,
61
+ opts: {
62
+ openidUser?: OidcUserInfo
63
+ tokenSet: Exclude<SessionContext['auth']['tokenSet'], undefined>
64
+ }
65
+ ) => Awaitable<AuthorizedUser>
66
+ }
67
+
68
+ type NuxtSessionContext<TData = Record<string, unknown>> = {
69
+ readonly id: string
70
+ readonly isAuthenticated: boolean
71
+ readonly user: AuthorizedUser
72
+ readonly data: TData
73
+ }
74
+
75
+ type NuxtSessionUpdateContext<TData = Record<string, unknown>> = DeepPartial<{
76
+ user: AuthorizedUser
77
+ data: TData
78
+ }>
79
+
80
+ /**
81
+ * OpenID Connect configuration options.
82
+ *
83
+ * Defines parameters used for client registration, discovery,
84
+ * and token exchange with the OpenID Provider.
85
+ *
86
+ * @since 1.0.0
87
+ */
88
+ type OpenIdOptions = {
89
+ /** Client ID registered with the OpenID Provider. */
90
+ clientId: string
91
+
92
+ /** Client secret for token exchange (if applicable). */
93
+ clientSecret: string
94
+
95
+ /** Whether to use Proof Key for Code Exchange (PKCE) flow. */
96
+ usePkce: boolean
97
+
98
+ /** Code challenge method, e.g. `S256`. */
99
+ codeChallengeMethod: string
100
+
101
+ /** Scopes requested from the OpenID Provider. */
102
+ scopes: string[]
103
+
104
+ /** Redirect URI used after authorization. */
105
+ redirectUri: string
106
+
107
+ /** The `.well-known/openid-configuration` discovery URL. */
108
+ wellKnownUrl: string
109
+
110
+ /** Whether to automatically fetch user info after login. */
111
+ autoFetchUser: boolean
112
+
113
+ /**
114
+ * TTL in seconds for caching autoFetchUser results per session.
115
+ * A GET_SESSION within the TTL window does not trigger an OIDC provider call.
116
+ * Only applies when autoFetchUser is true.
117
+ * @default 300
118
+ * @since 1.0.0
119
+ */
120
+ autoFetchUserTtl: number
121
+
122
+ /** Whether to fetch user info immediately after token grant. */
123
+ fetchUserOnLogin: boolean
124
+
125
+ /**
126
+ * Window in milliseconds before token expiry at which a refresh is triggered.
127
+ * Tokens with expiresAt more than this many milliseconds in the future are
128
+ * considered fresh and the refresh path is skipped entirely.
129
+ * @default 60000
130
+ * @since 1.0.0
131
+ */
132
+ tokenRefreshBufferMs: number
133
+
134
+ /**
135
+ * When `true`, the token refresh mutex uses an atomic Redis NX write
136
+ * (`SET key value NX EX ttl`) via the IORedis native client accessor for
137
+ * true distributed exclusion across multiple server instances. When `false`
138
+ * (default), the existing optimistic lock (`hasItem` + `setItem`) is used.
139
+ *
140
+ * @remarks Only effective when the Nitro `cache` storage mount is backed by
141
+ * a Redis driver. Setting `true` with a non-Redis backend falls through to
142
+ * the optimistic path silently.
143
+ *
144
+ * @default false
145
+ * @since 1.0.0
146
+ */
147
+ distributedLock?: boolean
148
+
149
+ /** Cache configuration for storing OpenID metadata. */
150
+ cache: {
151
+ /** Cache key prefix for the metadata store. */
152
+ prefix: string
153
+ /** Expiry time in seconds for cached metadata. */
154
+ expires: number
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Session management configuration.
160
+ *
161
+ * Defines session storage, expiration, and cookie behavior
162
+ * for authentication session tracking.
163
+ *
164
+ * @since 1.0.0
165
+ */
166
+ type SessionsOptions = {
167
+ /** Cookie name mappings used by the session handler. */
168
+ names: {
169
+ /** PKCE verifier cookie name. */
170
+ pkce: string
171
+ /** State cookie name. */
172
+ state: string
173
+ /** Session ID cookie name. */
174
+ sessionId: string
175
+ /** Redirect URL cookie name. */
176
+ redirectUrl: string
177
+ }
178
+
179
+ storage: {
180
+ name: string
181
+
182
+ /** Key prefix for session data in the storage backend. */
183
+ prefix: string
184
+ }
185
+
186
+ /**
187
+ * Session lifetime in seconds.
188
+ * Converted to milliseconds internally for Date.now() expiry calculations.
189
+ * Passed directly as Redis TTL (seconds).
190
+ * @default 518400 (6 days)
191
+ * @since 1.0.0
192
+ */
193
+ expiresIn: number
194
+
195
+ /** Options for how session cookies are serialized. */
196
+ cookieOpts: CookieSerializeOptions
197
+
198
+ /**
199
+ * Secret used to HMAC-sign session ID cookies and derive the AES-256-GCM key
200
+ * for tokenSet encryption. When empty, signing and encryption are skipped.
201
+ * @since 1.0.0
202
+ */
203
+ secret?: string
204
+ }
205
+
206
+ /**
207
+ * Authentication behavior configuration.
208
+ *
209
+ * Defines default redirect paths and URIs used for login/logout flow.
210
+ *
211
+ * @since 1.0.0
212
+ */
213
+ type AuthOptions = {
214
+ /** Path to the login page. */
215
+ loginUri: string
216
+
217
+ /** Default redirect URI after successful login. */
218
+ defaultLoginRedirectUri: string
219
+
220
+ /** Default redirect URI after logout. */
221
+ defaultLogoutRedirectUri: string
222
+
223
+ /** Default anonymous user object. */
224
+ anonymousUser: AuthorizedUser
225
+
226
+ ignoreRegexPatterns: RegExp[]
227
+
228
+ ignoreRegexPatternsDev: RegExp[]
229
+ }
230
+
231
+ /**
232
+ * Main configuration interface for the Nuxt AuthTS module.
233
+ *
234
+ * Combines OpenID Connect, session, and general authentication options.
235
+ *
236
+ * @since 1.0.0
237
+ */
238
+ type AuthtsModuleOptions = {
239
+ /** Enable or disable the module */
240
+ enabled: boolean
241
+ openid: OpenIdOptions
242
+ sessions: SessionsOptions
243
+ auth: AuthOptions
244
+ }
245
+
246
+ interface AuthtsMiddlewareMeta {
247
+ /** Require authentication to access */
248
+ required?: boolean
249
+
250
+ /** Only accessible if unauthenticated (login/register pages) */
251
+ unauthenticatedOnly?: boolean
252
+
253
+ /** Restrict access to these roles */
254
+ roles?: string[]
249
255
  }
250
256
 
251
257
  type CoreLogLevel = LogLevel$1
package/dist/module.d.ts CHANGED
@@ -3,249 +3,255 @@ import { CookieSerializeOptions } from '../dist/runtime/server/adapters/http.js'
3
3
  import { OidcUserInfo } from '../dist/runtime/server/adapters/oidc.js';
4
4
  import { LogLevel as LogLevel$1, ConsolaOptions, ConsolaInstance } from 'consola';
5
5
 
6
- interface AuthorizedUser {
7
- id: string
8
- sub: string
9
- email: string
10
- firstName: string
11
- lastName: string
12
- locale: string
13
- language: string
14
- timezone: string
15
- }
16
-
17
- type AuthStatus = 'unauthenticated' | 'authenticated'
18
-
19
- type AuthData = {
20
- status: AuthStatus
21
- tokenSet?: {
22
- accessToken: string
23
- tokenType: string
24
- expiresAt: number
25
- idToken: string
26
- refreshToken: string
27
- scopes: string[]
28
- }
29
- }
30
-
31
- type SessionContext<TData = Record<string, unknown>> = {
32
- id: string
33
- auth: AuthData
34
- user: AuthorizedUser
35
- data: TData
36
- issuedAt: number
37
- expiresAt: number
38
- }
39
-
40
- type NuxtAuthOptions = {
41
- /**
42
- * Default Devcoffee Nuxt AuthTS option callbacks for session and user mapping.
43
- * These can be overridden by passing custom callbacks to `NuxtAuthtsHandler()`.
44
- * @since 1.0.0
45
- */
46
- session: (
47
- session: Omit<SessionContext, 'auth'>,
48
- auth: SessionContext['auth']
49
- ) => Awaitable<Omit<SessionContext, 'auth' | 'issuedAt' | 'expiresAt'> & { isAuthenticated: boolean }>
50
-
51
- /**
52
- * Maps the OpenID Connect user info response to your local user schema.
53
- *
54
- * @param user - The raw user info response from the OpenID provider.
55
- * @param opts - The token response containing access and ID tokens.
56
- * @returns A normalized user object.
57
- * @since 1.0.0
58
- */
59
- userInfo: (
60
- user: AuthorizedUser,
61
- opts: {
62
- openidUser?: OidcUserInfo
63
- tokenSet: Exclude<SessionContext['auth']['tokenSet'], undefined>
64
- }
65
- ) => Awaitable<AuthorizedUser>
66
- }
67
-
68
- type NuxtSessionContext<TData = Record<string, unknown>> = {
69
- readonly id: string
70
- readonly isAuthenticated: boolean
71
- readonly user: AuthorizedUser
72
- readonly data: TData
73
- }
74
-
75
- type NuxtSessionUpdateContext<TData = Record<string, unknown>> = DeepPartial<{
76
- user: AuthorizedUser
77
- data: TData
78
- }>
79
-
80
- /**
81
- * ⚙️ OpenID Connect configuration options.
82
- *
83
- * Defines parameters used for client registration, discovery,
84
- * and token exchange with the OpenID Provider.
85
- *
86
- * @since 1.0.0
87
- */
88
- type OpenIdOptions = {
89
- /** Client ID registered with the OpenID Provider. */
90
- clientId: string
91
-
92
- /** Client secret for token exchange (if applicable). */
93
- clientSecret: string
94
-
95
- /** Whether to use Proof Key for Code Exchange (PKCE) flow. */
96
- usePkce: boolean
97
-
98
- /** Code challenge method, e.g. `S256`. */
99
- codeChallengeMethod: string
100
-
101
- /** Scopes requested from the OpenID Provider. */
102
- scopes: string[]
103
-
104
- /** Redirect URI used after authorization. */
105
- redirectUri: string
106
-
107
- /** The `.well-known/openid-configuration` discovery URL. */
108
- wellKnownUrl: string
109
-
110
- /** Whether to automatically fetch user info after login. */
111
- autoFetchUser: boolean
112
-
113
- /**
114
- * TTL in seconds for caching autoFetchUser results per session.
115
- * A GET_SESSION within the TTL window does not trigger an OIDC provider call.
116
- * Only applies when autoFetchUser is true.
117
- * @default 300
118
- * @since 1.0.0
119
- */
120
- autoFetchUserTtl: number
121
-
122
- /** Whether to fetch user info immediately after token grant. */
123
- fetchUserOnLogin: boolean
124
-
125
- /**
126
- * Window in milliseconds before token expiry at which a refresh is triggered.
127
- * Tokens with expiresAt more than this many milliseconds in the future are
128
- * considered fresh and the refresh path is skipped entirely.
129
- * @default 60000
130
- * @since 1.0.0
131
- */
132
- tokenRefreshBufferMs: number
133
-
134
- /**
135
- * When `true`, the token refresh mutex uses an atomic Redis NX write
136
- * (`SET key value NX EX ttl`) via the IORedis native client accessor for
137
- * true distributed exclusion across multiple server instances. When `false`
138
- * (default), the existing optimistic lock (`hasItem` + `setItem`) is used.
139
- *
140
- * @remarks Only effective when the Nitro `cache` storage mount is backed by
141
- * a Redis driver. Setting `true` with a non-Redis backend falls through to
142
- * the optimistic path silently.
143
- *
144
- * @default false
145
- * @since 1.0.0
146
- */
147
- distributedLock?: boolean
148
-
149
- /** Cache configuration for storing OpenID metadata. */
150
- cache: {
151
- /** Cache key prefix for the metadata store. */
152
- prefix: string
153
- /** Expiry time in seconds for cached metadata. */
154
- expires: number
155
- }
156
- }
157
-
158
- /**
159
- * 🍪 Session management configuration.
160
- *
161
- * Defines session storage, expiration, and cookie behavior
162
- * for authentication session tracking.
163
- *
164
- * @since 1.0.0
165
- */
166
- type SessionsOptions = {
167
- /** Cookie name mappings used by the session handler. */
168
- names: {
169
- /** PKCE verifier cookie name. */
170
- pkce: string
171
- /** State cookie name. */
172
- state: string
173
- /** Session ID cookie name. */
174
- sessionId: string
175
- /** Redirect URL cookie name. */
176
- redirectUrl: string
177
- }
178
-
179
- storage: {
180
- name: string
181
-
182
- /** Key prefix for session data in the storage backend. */
183
- prefix: string
184
- }
185
-
186
- /** Session lifetime in seconds. */
187
- expiresIn: number
188
-
189
- /** Options for how session cookies are serialized. */
190
- cookieOpts: CookieSerializeOptions
191
-
192
- /**
193
- * Secret used to HMAC-sign session ID cookies and derive the AES-256-GCM key
194
- * for tokenSet encryption. When empty, signing and encryption are skipped.
195
- * @since 1.0.0
196
- */
197
- secret?: string
198
- }
199
-
200
- /**
201
- * 🔐 Authentication behavior configuration.
202
- *
203
- * Defines default redirect paths and URIs used for login/logout flow.
204
- *
205
- * @since 1.0.0
206
- */
207
- type AuthOptions = {
208
- /** Path to the login page. */
209
- loginUri: string
210
-
211
- /** Default redirect URI after successful login. */
212
- defaultLoginRedirectUri: string
213
-
214
- /** Default redirect URI after logout. */
215
- defaultLogoutRedirectUri: string
216
-
217
- /** Default anonymous user object. */
218
- anonymousUser: AuthorizedUser
219
-
220
- ignoreRegexPatterns: RegExp[]
221
-
222
- ignoreRegexPatternsDev: RegExp[]
223
- }
224
-
225
- /**
226
- * 🧩 Main configuration interface for the Nuxt AuthTS module.
227
- *
228
- * Combines OpenID Connect, session, and general authentication options.
229
- *
230
- * @since 1.0.0
231
- */
232
- type AuthtsModuleOptions = {
233
- /** Enable or disable the module */
234
- enabled: boolean
235
- openid: OpenIdOptions
236
- sessions: SessionsOptions
237
- auth: AuthOptions
238
- }
239
-
240
- interface AuthtsMiddlewareMeta {
241
- /** Require authentication to access */
242
- required?: boolean
243
-
244
- /** Only accessible if unauthenticated (login/register pages) */
245
- unauthenticatedOnly?: boolean
246
-
247
- /** Restrict access to these roles */
248
- roles?: string[]
6
+ interface AuthorizedUser {
7
+ id: string
8
+ sub: string
9
+ email: string
10
+ firstName: string
11
+ lastName: string
12
+ locale: string
13
+ language: string
14
+ timezone: string
15
+ }
16
+
17
+ type AuthStatus = 'unauthenticated' | 'authenticated'
18
+
19
+ type AuthData = {
20
+ status: AuthStatus
21
+ tokenSet?: {
22
+ accessToken: string
23
+ tokenType: string
24
+ expiresAt: number
25
+ idToken: string
26
+ refreshToken: string
27
+ scopes: string[]
28
+ }
29
+ }
30
+
31
+ type SessionContext<TData = Record<string, unknown>> = {
32
+ id: string
33
+ auth: AuthData
34
+ user: AuthorizedUser
35
+ data: TData
36
+ issuedAt: number
37
+ expiresAt: number
38
+ }
39
+
40
+ type NuxtAuthOptions = {
41
+ /**
42
+ * Default Devcoffee Nuxt AuthTS option callbacks for session and user mapping.
43
+ * These can be overridden by passing custom callbacks to `NuxtAuthtsHandler()`.
44
+ * @since 1.0.0
45
+ */
46
+ session: (
47
+ session: Omit<SessionContext, 'auth'>,
48
+ auth: SessionContext['auth']
49
+ ) => Awaitable<Omit<SessionContext, 'auth' | 'issuedAt' | 'expiresAt'> & { isAuthenticated: boolean }>
50
+
51
+ /**
52
+ * Maps the OpenID Connect user info response to your local user schema.
53
+ *
54
+ * @param user - The raw user info response from the OpenID provider.
55
+ * @param opts - The token response containing access and ID tokens.
56
+ * @returns A normalized user object.
57
+ * @since 1.0.0
58
+ */
59
+ userInfo: (
60
+ user: AuthorizedUser,
61
+ opts: {
62
+ openidUser?: OidcUserInfo
63
+ tokenSet: Exclude<SessionContext['auth']['tokenSet'], undefined>
64
+ }
65
+ ) => Awaitable<AuthorizedUser>
66
+ }
67
+
68
+ type NuxtSessionContext<TData = Record<string, unknown>> = {
69
+ readonly id: string
70
+ readonly isAuthenticated: boolean
71
+ readonly user: AuthorizedUser
72
+ readonly data: TData
73
+ }
74
+
75
+ type NuxtSessionUpdateContext<TData = Record<string, unknown>> = DeepPartial<{
76
+ user: AuthorizedUser
77
+ data: TData
78
+ }>
79
+
80
+ /**
81
+ * OpenID Connect configuration options.
82
+ *
83
+ * Defines parameters used for client registration, discovery,
84
+ * and token exchange with the OpenID Provider.
85
+ *
86
+ * @since 1.0.0
87
+ */
88
+ type OpenIdOptions = {
89
+ /** Client ID registered with the OpenID Provider. */
90
+ clientId: string
91
+
92
+ /** Client secret for token exchange (if applicable). */
93
+ clientSecret: string
94
+
95
+ /** Whether to use Proof Key for Code Exchange (PKCE) flow. */
96
+ usePkce: boolean
97
+
98
+ /** Code challenge method, e.g. `S256`. */
99
+ codeChallengeMethod: string
100
+
101
+ /** Scopes requested from the OpenID Provider. */
102
+ scopes: string[]
103
+
104
+ /** Redirect URI used after authorization. */
105
+ redirectUri: string
106
+
107
+ /** The `.well-known/openid-configuration` discovery URL. */
108
+ wellKnownUrl: string
109
+
110
+ /** Whether to automatically fetch user info after login. */
111
+ autoFetchUser: boolean
112
+
113
+ /**
114
+ * TTL in seconds for caching autoFetchUser results per session.
115
+ * A GET_SESSION within the TTL window does not trigger an OIDC provider call.
116
+ * Only applies when autoFetchUser is true.
117
+ * @default 300
118
+ * @since 1.0.0
119
+ */
120
+ autoFetchUserTtl: number
121
+
122
+ /** Whether to fetch user info immediately after token grant. */
123
+ fetchUserOnLogin: boolean
124
+
125
+ /**
126
+ * Window in milliseconds before token expiry at which a refresh is triggered.
127
+ * Tokens with expiresAt more than this many milliseconds in the future are
128
+ * considered fresh and the refresh path is skipped entirely.
129
+ * @default 60000
130
+ * @since 1.0.0
131
+ */
132
+ tokenRefreshBufferMs: number
133
+
134
+ /**
135
+ * When `true`, the token refresh mutex uses an atomic Redis NX write
136
+ * (`SET key value NX EX ttl`) via the IORedis native client accessor for
137
+ * true distributed exclusion across multiple server instances. When `false`
138
+ * (default), the existing optimistic lock (`hasItem` + `setItem`) is used.
139
+ *
140
+ * @remarks Only effective when the Nitro `cache` storage mount is backed by
141
+ * a Redis driver. Setting `true` with a non-Redis backend falls through to
142
+ * the optimistic path silently.
143
+ *
144
+ * @default false
145
+ * @since 1.0.0
146
+ */
147
+ distributedLock?: boolean
148
+
149
+ /** Cache configuration for storing OpenID metadata. */
150
+ cache: {
151
+ /** Cache key prefix for the metadata store. */
152
+ prefix: string
153
+ /** Expiry time in seconds for cached metadata. */
154
+ expires: number
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Session management configuration.
160
+ *
161
+ * Defines session storage, expiration, and cookie behavior
162
+ * for authentication session tracking.
163
+ *
164
+ * @since 1.0.0
165
+ */
166
+ type SessionsOptions = {
167
+ /** Cookie name mappings used by the session handler. */
168
+ names: {
169
+ /** PKCE verifier cookie name. */
170
+ pkce: string
171
+ /** State cookie name. */
172
+ state: string
173
+ /** Session ID cookie name. */
174
+ sessionId: string
175
+ /** Redirect URL cookie name. */
176
+ redirectUrl: string
177
+ }
178
+
179
+ storage: {
180
+ name: string
181
+
182
+ /** Key prefix for session data in the storage backend. */
183
+ prefix: string
184
+ }
185
+
186
+ /**
187
+ * Session lifetime in seconds.
188
+ * Converted to milliseconds internally for Date.now() expiry calculations.
189
+ * Passed directly as Redis TTL (seconds).
190
+ * @default 518400 (6 days)
191
+ * @since 1.0.0
192
+ */
193
+ expiresIn: number
194
+
195
+ /** Options for how session cookies are serialized. */
196
+ cookieOpts: CookieSerializeOptions
197
+
198
+ /**
199
+ * Secret used to HMAC-sign session ID cookies and derive the AES-256-GCM key
200
+ * for tokenSet encryption. When empty, signing and encryption are skipped.
201
+ * @since 1.0.0
202
+ */
203
+ secret?: string
204
+ }
205
+
206
+ /**
207
+ * Authentication behavior configuration.
208
+ *
209
+ * Defines default redirect paths and URIs used for login/logout flow.
210
+ *
211
+ * @since 1.0.0
212
+ */
213
+ type AuthOptions = {
214
+ /** Path to the login page. */
215
+ loginUri: string
216
+
217
+ /** Default redirect URI after successful login. */
218
+ defaultLoginRedirectUri: string
219
+
220
+ /** Default redirect URI after logout. */
221
+ defaultLogoutRedirectUri: string
222
+
223
+ /** Default anonymous user object. */
224
+ anonymousUser: AuthorizedUser
225
+
226
+ ignoreRegexPatterns: RegExp[]
227
+
228
+ ignoreRegexPatternsDev: RegExp[]
229
+ }
230
+
231
+ /**
232
+ * Main configuration interface for the Nuxt AuthTS module.
233
+ *
234
+ * Combines OpenID Connect, session, and general authentication options.
235
+ *
236
+ * @since 1.0.0
237
+ */
238
+ type AuthtsModuleOptions = {
239
+ /** Enable or disable the module */
240
+ enabled: boolean
241
+ openid: OpenIdOptions
242
+ sessions: SessionsOptions
243
+ auth: AuthOptions
244
+ }
245
+
246
+ interface AuthtsMiddlewareMeta {
247
+ /** Require authentication to access */
248
+ required?: boolean
249
+
250
+ /** Only accessible if unauthenticated (login/register pages) */
251
+ unauthenticatedOnly?: boolean
252
+
253
+ /** Restrict access to these roles */
254
+ roles?: string[]
249
255
  }
250
256
 
251
257
  type CoreLogLevel = LogLevel$1
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-core",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "configKey": "nuxtCore",
5
5
  "compatibility": {
6
6
  "nuxt": "^4.0.0"
package/dist/module.mjs CHANGED
@@ -2,7 +2,7 @@ import { addCustomTab } from '@nuxt/devtools-kit';
2
2
  import { defineNuxtModule, useLogger, createResolver, addTemplate, addServerImports, addServerImportsDir, addServerPlugin, addImportsDir, addPlugin, addRouteMiddleware, addServerHandler } from '@nuxt/kit';
3
3
  import { deepMerge, pick } from '../dist/runtime/utils.js';
4
4
 
5
- const version = "1.4.0";
5
+ const version = "1.4.1";
6
6
 
7
7
  const defaultLocale = "vi-VN";
8
8
  const defaultLanguage = "vi";
@@ -50,7 +50,7 @@ const authtsDefaults = {
50
50
  },
51
51
  storage: { name: "sessions", prefix: "session" },
52
52
  expiresIn: 60 * 60 * 24 * 6,
53
- // 6 days
53
+ // 6 days in seconds
54
54
  cookieOpts: {
55
55
  path: "/",
56
56
  sameSite: "lax",
@@ -71,7 +71,7 @@ export declare function validateSession(sessionCookieId: string | undefined, opt
71
71
  *
72
72
  * @param sessionId - The session ID.
73
73
  * @param input - Partial update fields for the session (excluding ID, issuedAt, expiresAt).
74
- * @param opts - Expiration configuration (in milliseconds).
74
+ * @param opts - Expiration configuration (expiresIn in seconds).
75
75
  * @returns The updated {@link SessionContext}.
76
76
  * @throws {Error} If session cannot be found in storage.
77
77
  * @since 1.0.0
@@ -106,7 +106,7 @@ function newSession(sessionId, expiresAt) {
106
106
  }
107
107
  export async function validateSession(sessionCookieId, opts) {
108
108
  const now = Date.now();
109
- const expiresAt = now + opts.expiresIn;
109
+ const expiresAt = now + opts.expiresIn * 1e3;
110
110
  let sessionId = void 0;
111
111
  let sessionKey = void 0;
112
112
  let deleteSessionKey = void 0;
@@ -133,7 +133,7 @@ export async function validateSession(sessionCookieId, opts) {
133
133
  if (deleteSessionKey && deleteSessionKey !== sessionKey) {
134
134
  await removeSessionData(opts.storageName, deleteSessionKey);
135
135
  }
136
- await setSessionData(opts.storageName, sessionKey, session, opts.expiresIn / 1e3 | 0);
136
+ await setSessionData(opts.storageName, sessionKey, session, opts.expiresIn);
137
137
  if (session.auth?.tokenSet && session.auth.tokenSet.encrypted === true) {
138
138
  if (opts.secret) {
139
139
  const decrypted = decryptTokenSet(session.auth.tokenSet, opts.secret);
@@ -160,7 +160,7 @@ export async function updateSession(sessionId, input, opts) {
160
160
  });
161
161
  }
162
162
  session = deepMerge({}, session, normalizedInput);
163
- session.expiresAt = now + opts.expiresIn;
163
+ session.expiresAt = now + opts.expiresIn * 1e3;
164
164
  const sessionToStore = { ...session };
165
165
  if (opts.secret && sessionToStore.auth?.tokenSet) {
166
166
  sessionToStore.auth = {
@@ -171,7 +171,7 @@ export async function updateSession(sessionId, input, opts) {
171
171
  )
172
172
  };
173
173
  }
174
- await setSessionData(opts.storageName, serverKey, sessionToStore, opts.expiresIn / 1e3 | 0);
174
+ await setSessionData(opts.storageName, serverKey, sessionToStore, opts.expiresIn);
175
175
  return session;
176
176
  }
177
177
  export async function renewSession(sessionId, opts) {
@@ -179,9 +179,9 @@ export async function renewSession(sessionId, opts) {
179
179
  if (await hasSessionData(opts.storageName, sessionKey)) {
180
180
  await removeSessionData(opts.storageName, sessionKey);
181
181
  }
182
- const session = newSession(generateSessionId(), Date.now() + opts.expiresIn);
182
+ const session = newSession(generateSessionId(), Date.now() + opts.expiresIn * 1e3);
183
183
  sessionKey = getSessionStorageKey(opts.storagePrefix, session.id);
184
- await setSessionData(opts.storageName, sessionKey, session, opts.expiresIn / 1e3 | 0);
184
+ await setSessionData(opts.storageName, sessionKey, session, opts.expiresIn);
185
185
  return session;
186
186
  }
187
187
  export async function deleteSession(sessionId, opts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devcoffee/nuxt-core",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -53,7 +53,7 @@
53
53
  "cleanup": "nuxi cleanup && nuxi cleanup playground",
54
54
  "dev:build": "nuxi build playground",
55
55
  "prepack": "nuxt-module-build build",
56
- "release": "npm run lint && npm run test:all && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
56
+ "release": "npm run lint && npm run test:all && npm run prepack && npm publish && git push --follow-tags",
57
57
  "lint": "eslint",
58
58
  "lint:fix": "eslint --fix",
59
59
  "test": "cross-env NODE_OPTIONS=--no-deprecation vitest run test/unit",