formreader-session-timeout 0.2.4 → 0.2.6
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/dist/index.d.ts +32 -3
- package/dist/index.js +104 -7
- package/dist/index.mjs +101 -7
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -48,7 +48,7 @@ interface SessionConfig {
|
|
|
48
48
|
/** Custom function to format the refresh request payload */
|
|
49
49
|
refreshPayloadFormatter?: (token: string, refreshToken: string) => Record<string, any>;
|
|
50
50
|
/** Custom function to format the logout request payload */
|
|
51
|
-
logoutPayloadFormatter?: (token: string) => Record<string, any>;
|
|
51
|
+
logoutPayloadFormatter?: (token: string, refreshToken?: string) => Record<string, any>;
|
|
52
52
|
/** Which field in login response contains access token (default: 'access') */
|
|
53
53
|
accessTokenField?: string;
|
|
54
54
|
/** Which field in login response contains refresh token (default: 'refresh') */
|
|
@@ -59,6 +59,10 @@ interface SessionConfig {
|
|
|
59
59
|
refreshRefreshTokenField?: string;
|
|
60
60
|
/** Whether to store refresh token separately (default: true) */
|
|
61
61
|
storeRefreshToken?: boolean;
|
|
62
|
+
/** Whether to validate token on page reload/initialization (default: true) */
|
|
63
|
+
validateOnInit?: boolean;
|
|
64
|
+
/** Custom token validation endpoint for server-side validation */
|
|
65
|
+
tokenValidationEndpoint?: string;
|
|
62
66
|
}
|
|
63
67
|
interface JWTPayload {
|
|
64
68
|
exp: number;
|
|
@@ -130,9 +134,16 @@ declare class SessionManager {
|
|
|
130
134
|
*/
|
|
131
135
|
logout(): Promise<void>;
|
|
132
136
|
/**
|
|
133
|
-
* Check if session is active
|
|
137
|
+
* Check if session is active and token is valid
|
|
134
138
|
*/
|
|
135
139
|
isActive(): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Validate current session without initializing
|
|
142
|
+
*/
|
|
143
|
+
validateSession(): {
|
|
144
|
+
isValid: boolean;
|
|
145
|
+
reason?: string;
|
|
146
|
+
};
|
|
136
147
|
/**
|
|
137
148
|
* Get current state
|
|
138
149
|
*/
|
|
@@ -207,6 +218,24 @@ declare function clearToken(): void;
|
|
|
207
218
|
*/
|
|
208
219
|
declare function validateToken(token: string): boolean;
|
|
209
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Authentication utilities for session validation
|
|
223
|
+
*/
|
|
224
|
+
/**
|
|
225
|
+
* Check if user is authenticated with valid token
|
|
226
|
+
* This is the function to use in your App.tsx for page reload validation
|
|
227
|
+
*/
|
|
228
|
+
declare function isAuthenticated(): boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Initialize session with token validation on page reload
|
|
231
|
+
* Returns a promise that resolves to authentication status
|
|
232
|
+
*/
|
|
233
|
+
declare function initializeAuth(config?: any): Promise<boolean>;
|
|
234
|
+
/**
|
|
235
|
+
* Trigger auth change event for cross-tab synchronization
|
|
236
|
+
*/
|
|
237
|
+
declare function triggerAuthChange(): void;
|
|
238
|
+
|
|
210
239
|
/**
|
|
211
240
|
* useSessionTimeout Hook
|
|
212
241
|
* React hook for managing session timeout
|
|
@@ -242,4 +271,4 @@ declare function useSessionTimeout(options?: UseSessionTimeoutOptions): {
|
|
|
242
271
|
*/
|
|
243
272
|
declare function SessionStatus(): react_jsx_runtime.JSX.Element;
|
|
244
273
|
|
|
245
|
-
export { DEFAULT_SESSION_CONFIG, JWTPayload, RefreshTokenResponse, SessionConfig, SessionManager, SessionState, SessionStatus, TokenInfo, UseSessionTimeoutOptions, clearToken, getSessionManager, getStoredRefreshToken, getStoredToken, getTimeUntilExpiry, getTokenInfo, isTokenExpired, resetSessionManager, storeRefreshToken, storeToken, useSessionTimeout, validateToken };
|
|
274
|
+
export { DEFAULT_SESSION_CONFIG, JWTPayload, RefreshTokenResponse, SessionConfig, SessionManager, SessionState, SessionStatus, TokenInfo, UseSessionTimeoutOptions, clearToken, getSessionManager, getStoredRefreshToken, getStoredToken, getTimeUntilExpiry, getTokenInfo, initializeAuth, isAuthenticated, isTokenExpired, resetSessionManager, storeRefreshToken, storeToken, triggerAuthChange, useSessionTimeout, validateToken };
|
package/dist/index.js
CHANGED
|
@@ -28,10 +28,13 @@ __export(session_timeout_exports, {
|
|
|
28
28
|
getStoredToken: () => getStoredToken,
|
|
29
29
|
getTimeUntilExpiry: () => getTimeUntilExpiry,
|
|
30
30
|
getTokenInfo: () => getTokenInfo,
|
|
31
|
+
initializeAuth: () => initializeAuth,
|
|
32
|
+
isAuthenticated: () => isAuthenticated,
|
|
31
33
|
isTokenExpired: () => isTokenExpired,
|
|
32
34
|
resetSessionManager: () => resetSessionManager,
|
|
33
35
|
storeRefreshToken: () => storeRefreshToken,
|
|
34
36
|
storeToken: () => storeToken,
|
|
37
|
+
triggerAuthChange: () => triggerAuthChange,
|
|
35
38
|
useSessionTimeout: () => useSessionTimeout,
|
|
36
39
|
validateToken: () => validateToken
|
|
37
40
|
});
|
|
@@ -59,7 +62,8 @@ var DEFAULT_SESSION_CONFIG = {
|
|
|
59
62
|
refreshTokenField: "refresh",
|
|
60
63
|
refreshAccessTokenField: "access",
|
|
61
64
|
refreshRefreshTokenField: "refresh",
|
|
62
|
-
storeRefreshToken: true
|
|
65
|
+
storeRefreshToken: true,
|
|
66
|
+
validateOnInit: true
|
|
63
67
|
};
|
|
64
68
|
|
|
65
69
|
// services/tokenService.ts
|
|
@@ -191,6 +195,7 @@ var SessionManager = class {
|
|
|
191
195
|
const token = loginResponse ? extractTokenFromResponse(loginResponse, this.config.accessTokenField || "access") : getStoredToken();
|
|
192
196
|
if (!token) {
|
|
193
197
|
this.log("No token found, session not initialized");
|
|
198
|
+
this.emit("noToken");
|
|
194
199
|
return;
|
|
195
200
|
}
|
|
196
201
|
storeToken(token);
|
|
@@ -206,10 +211,27 @@ var SessionManager = class {
|
|
|
206
211
|
}
|
|
207
212
|
const validation = validateToken(token);
|
|
208
213
|
if (!validation) {
|
|
209
|
-
this.log("Invalid token");
|
|
214
|
+
this.log("Invalid token format");
|
|
215
|
+
this.emit("invalidToken");
|
|
210
216
|
this.logout();
|
|
211
217
|
return;
|
|
212
218
|
}
|
|
219
|
+
if (isTokenExpired(token)) {
|
|
220
|
+
this.log("Token is expired, attempting refresh");
|
|
221
|
+
this.emit("tokenExpired");
|
|
222
|
+
const refreshToken = getStoredRefreshToken();
|
|
223
|
+
if (refreshToken && this.config.autoRefresh) {
|
|
224
|
+
this.refreshToken().then((success) => {
|
|
225
|
+
if (!success) {
|
|
226
|
+
this.logout();
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
} else {
|
|
231
|
+
this.logout();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
213
235
|
this.state.isActive = true;
|
|
214
236
|
this.setupTokenRefresh();
|
|
215
237
|
this.setupIdleTracking();
|
|
@@ -303,7 +325,7 @@ var SessionManager = class {
|
|
|
303
325
|
try {
|
|
304
326
|
this.log(`Refreshing token (attempt ${this.state.refreshAttempts})`);
|
|
305
327
|
const client = this.config.httpClient || defaultFetchClient();
|
|
306
|
-
const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken
|
|
328
|
+
const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken) : {
|
|
307
329
|
refresh: refreshToken || accessToken,
|
|
308
330
|
token: accessToken
|
|
309
331
|
};
|
|
@@ -367,7 +389,7 @@ var SessionManager = class {
|
|
|
367
389
|
const token = getStoredToken();
|
|
368
390
|
if (token && this.config.logoutEndpoint) {
|
|
369
391
|
const client = this.config.httpClient || defaultFetchClient();
|
|
370
|
-
const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token) : { token };
|
|
392
|
+
const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token, getStoredRefreshToken()) : { token };
|
|
371
393
|
await client.post(this.config.logoutEndpoint, logoutPayload, {
|
|
372
394
|
headers: { Authorization: `Bearer ${token}` }
|
|
373
395
|
});
|
|
@@ -377,15 +399,36 @@ var SessionManager = class {
|
|
|
377
399
|
}
|
|
378
400
|
clearToken();
|
|
379
401
|
this.state.isActive = false;
|
|
380
|
-
this.emit("
|
|
402
|
+
this.emit("loggedOut");
|
|
381
403
|
(_b = (_a = this.config).onLogout) == null ? void 0 : _b.call(_a);
|
|
382
404
|
this.cleanup();
|
|
383
405
|
}
|
|
384
406
|
/**
|
|
385
|
-
* Check if session is active
|
|
407
|
+
* Check if session is active and token is valid
|
|
386
408
|
*/
|
|
387
409
|
isActive() {
|
|
388
|
-
|
|
410
|
+
if (!this.state.isActive)
|
|
411
|
+
return false;
|
|
412
|
+
const token = getStoredToken();
|
|
413
|
+
if (!token)
|
|
414
|
+
return false;
|
|
415
|
+
return !isTokenExpired(token);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Validate current session without initializing
|
|
419
|
+
*/
|
|
420
|
+
validateSession() {
|
|
421
|
+
const token = getStoredToken();
|
|
422
|
+
if (!token) {
|
|
423
|
+
return { isValid: false, reason: "no_token" };
|
|
424
|
+
}
|
|
425
|
+
if (!validateToken(token)) {
|
|
426
|
+
return { isValid: false, reason: "invalid_token" };
|
|
427
|
+
}
|
|
428
|
+
if (isTokenExpired(token)) {
|
|
429
|
+
return { isValid: false, reason: "token_expired" };
|
|
430
|
+
}
|
|
431
|
+
return { isValid: true };
|
|
389
432
|
}
|
|
390
433
|
/**
|
|
391
434
|
* Get current state
|
|
@@ -484,6 +527,57 @@ function resetSessionManager() {
|
|
|
484
527
|
}
|
|
485
528
|
}
|
|
486
529
|
|
|
530
|
+
// utils/authUtils.ts
|
|
531
|
+
function isAuthenticated() {
|
|
532
|
+
const token = getStoredToken();
|
|
533
|
+
if (!token) {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
if (!validateToken(token)) {
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
if (isTokenExpired(token)) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
async function initializeAuth(config) {
|
|
545
|
+
const manager = getSessionManager(config);
|
|
546
|
+
return new Promise((resolve) => {
|
|
547
|
+
const cleanup = [];
|
|
548
|
+
cleanup.push(manager.on("initialized", () => {
|
|
549
|
+
cleanup.forEach((fn) => fn());
|
|
550
|
+
resolve(true);
|
|
551
|
+
}));
|
|
552
|
+
cleanup.push(manager.on("noToken", () => {
|
|
553
|
+
cleanup.forEach((fn) => fn());
|
|
554
|
+
resolve(false);
|
|
555
|
+
}));
|
|
556
|
+
cleanup.push(manager.on("invalidToken", () => {
|
|
557
|
+
cleanup.forEach((fn) => fn());
|
|
558
|
+
resolve(false);
|
|
559
|
+
}));
|
|
560
|
+
cleanup.push(manager.on("tokenExpired", () => {
|
|
561
|
+
setTimeout(() => {
|
|
562
|
+
cleanup.forEach((fn) => fn());
|
|
563
|
+
resolve(manager.isActive());
|
|
564
|
+
}, 1e3);
|
|
565
|
+
}));
|
|
566
|
+
cleanup.push(manager.on("loggedOut", () => {
|
|
567
|
+
cleanup.forEach((fn) => fn());
|
|
568
|
+
resolve(false);
|
|
569
|
+
}));
|
|
570
|
+
manager.init();
|
|
571
|
+
setTimeout(() => {
|
|
572
|
+
cleanup.forEach((fn) => fn());
|
|
573
|
+
resolve(manager.isActive());
|
|
574
|
+
}, 3e3);
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
function triggerAuthChange() {
|
|
578
|
+
window.dispatchEvent(new CustomEvent("authChange"));
|
|
579
|
+
}
|
|
580
|
+
|
|
487
581
|
// hooks/useSessionTimeout.ts
|
|
488
582
|
var import_react = require("react");
|
|
489
583
|
function useSessionTimeout(options = {}) {
|
|
@@ -633,10 +727,13 @@ function SessionStatus() {
|
|
|
633
727
|
getStoredToken,
|
|
634
728
|
getTimeUntilExpiry,
|
|
635
729
|
getTokenInfo,
|
|
730
|
+
initializeAuth,
|
|
731
|
+
isAuthenticated,
|
|
636
732
|
isTokenExpired,
|
|
637
733
|
resetSessionManager,
|
|
638
734
|
storeRefreshToken,
|
|
639
735
|
storeToken,
|
|
736
|
+
triggerAuthChange,
|
|
640
737
|
useSessionTimeout,
|
|
641
738
|
validateToken
|
|
642
739
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -20,7 +20,8 @@ var DEFAULT_SESSION_CONFIG = {
|
|
|
20
20
|
refreshTokenField: "refresh",
|
|
21
21
|
refreshAccessTokenField: "access",
|
|
22
22
|
refreshRefreshTokenField: "refresh",
|
|
23
|
-
storeRefreshToken: true
|
|
23
|
+
storeRefreshToken: true,
|
|
24
|
+
validateOnInit: true
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
// services/tokenService.ts
|
|
@@ -152,6 +153,7 @@ var SessionManager = class {
|
|
|
152
153
|
const token = loginResponse ? extractTokenFromResponse(loginResponse, this.config.accessTokenField || "access") : getStoredToken();
|
|
153
154
|
if (!token) {
|
|
154
155
|
this.log("No token found, session not initialized");
|
|
156
|
+
this.emit("noToken");
|
|
155
157
|
return;
|
|
156
158
|
}
|
|
157
159
|
storeToken(token);
|
|
@@ -167,10 +169,27 @@ var SessionManager = class {
|
|
|
167
169
|
}
|
|
168
170
|
const validation = validateToken(token);
|
|
169
171
|
if (!validation) {
|
|
170
|
-
this.log("Invalid token");
|
|
172
|
+
this.log("Invalid token format");
|
|
173
|
+
this.emit("invalidToken");
|
|
171
174
|
this.logout();
|
|
172
175
|
return;
|
|
173
176
|
}
|
|
177
|
+
if (isTokenExpired(token)) {
|
|
178
|
+
this.log("Token is expired, attempting refresh");
|
|
179
|
+
this.emit("tokenExpired");
|
|
180
|
+
const refreshToken = getStoredRefreshToken();
|
|
181
|
+
if (refreshToken && this.config.autoRefresh) {
|
|
182
|
+
this.refreshToken().then((success) => {
|
|
183
|
+
if (!success) {
|
|
184
|
+
this.logout();
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
return;
|
|
188
|
+
} else {
|
|
189
|
+
this.logout();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
174
193
|
this.state.isActive = true;
|
|
175
194
|
this.setupTokenRefresh();
|
|
176
195
|
this.setupIdleTracking();
|
|
@@ -264,7 +283,7 @@ var SessionManager = class {
|
|
|
264
283
|
try {
|
|
265
284
|
this.log(`Refreshing token (attempt ${this.state.refreshAttempts})`);
|
|
266
285
|
const client = this.config.httpClient || defaultFetchClient();
|
|
267
|
-
const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken
|
|
286
|
+
const refreshPayload = this.config.refreshPayloadFormatter ? this.config.refreshPayloadFormatter(accessToken || "", refreshToken) : {
|
|
268
287
|
refresh: refreshToken || accessToken,
|
|
269
288
|
token: accessToken
|
|
270
289
|
};
|
|
@@ -328,7 +347,7 @@ var SessionManager = class {
|
|
|
328
347
|
const token = getStoredToken();
|
|
329
348
|
if (token && this.config.logoutEndpoint) {
|
|
330
349
|
const client = this.config.httpClient || defaultFetchClient();
|
|
331
|
-
const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token) : { token };
|
|
350
|
+
const logoutPayload = this.config.logoutPayloadFormatter ? this.config.logoutPayloadFormatter(token, getStoredRefreshToken()) : { token };
|
|
332
351
|
await client.post(this.config.logoutEndpoint, logoutPayload, {
|
|
333
352
|
headers: { Authorization: `Bearer ${token}` }
|
|
334
353
|
});
|
|
@@ -338,15 +357,36 @@ var SessionManager = class {
|
|
|
338
357
|
}
|
|
339
358
|
clearToken();
|
|
340
359
|
this.state.isActive = false;
|
|
341
|
-
this.emit("
|
|
360
|
+
this.emit("loggedOut");
|
|
342
361
|
(_b = (_a = this.config).onLogout) == null ? void 0 : _b.call(_a);
|
|
343
362
|
this.cleanup();
|
|
344
363
|
}
|
|
345
364
|
/**
|
|
346
|
-
* Check if session is active
|
|
365
|
+
* Check if session is active and token is valid
|
|
347
366
|
*/
|
|
348
367
|
isActive() {
|
|
349
|
-
|
|
368
|
+
if (!this.state.isActive)
|
|
369
|
+
return false;
|
|
370
|
+
const token = getStoredToken();
|
|
371
|
+
if (!token)
|
|
372
|
+
return false;
|
|
373
|
+
return !isTokenExpired(token);
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Validate current session without initializing
|
|
377
|
+
*/
|
|
378
|
+
validateSession() {
|
|
379
|
+
const token = getStoredToken();
|
|
380
|
+
if (!token) {
|
|
381
|
+
return { isValid: false, reason: "no_token" };
|
|
382
|
+
}
|
|
383
|
+
if (!validateToken(token)) {
|
|
384
|
+
return { isValid: false, reason: "invalid_token" };
|
|
385
|
+
}
|
|
386
|
+
if (isTokenExpired(token)) {
|
|
387
|
+
return { isValid: false, reason: "token_expired" };
|
|
388
|
+
}
|
|
389
|
+
return { isValid: true };
|
|
350
390
|
}
|
|
351
391
|
/**
|
|
352
392
|
* Get current state
|
|
@@ -445,6 +485,57 @@ function resetSessionManager() {
|
|
|
445
485
|
}
|
|
446
486
|
}
|
|
447
487
|
|
|
488
|
+
// utils/authUtils.ts
|
|
489
|
+
function isAuthenticated() {
|
|
490
|
+
const token = getStoredToken();
|
|
491
|
+
if (!token) {
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
if (!validateToken(token)) {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
if (isTokenExpired(token)) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
async function initializeAuth(config) {
|
|
503
|
+
const manager = getSessionManager(config);
|
|
504
|
+
return new Promise((resolve) => {
|
|
505
|
+
const cleanup = [];
|
|
506
|
+
cleanup.push(manager.on("initialized", () => {
|
|
507
|
+
cleanup.forEach((fn) => fn());
|
|
508
|
+
resolve(true);
|
|
509
|
+
}));
|
|
510
|
+
cleanup.push(manager.on("noToken", () => {
|
|
511
|
+
cleanup.forEach((fn) => fn());
|
|
512
|
+
resolve(false);
|
|
513
|
+
}));
|
|
514
|
+
cleanup.push(manager.on("invalidToken", () => {
|
|
515
|
+
cleanup.forEach((fn) => fn());
|
|
516
|
+
resolve(false);
|
|
517
|
+
}));
|
|
518
|
+
cleanup.push(manager.on("tokenExpired", () => {
|
|
519
|
+
setTimeout(() => {
|
|
520
|
+
cleanup.forEach((fn) => fn());
|
|
521
|
+
resolve(manager.isActive());
|
|
522
|
+
}, 1e3);
|
|
523
|
+
}));
|
|
524
|
+
cleanup.push(manager.on("loggedOut", () => {
|
|
525
|
+
cleanup.forEach((fn) => fn());
|
|
526
|
+
resolve(false);
|
|
527
|
+
}));
|
|
528
|
+
manager.init();
|
|
529
|
+
setTimeout(() => {
|
|
530
|
+
cleanup.forEach((fn) => fn());
|
|
531
|
+
resolve(manager.isActive());
|
|
532
|
+
}, 3e3);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
function triggerAuthChange() {
|
|
536
|
+
window.dispatchEvent(new CustomEvent("authChange"));
|
|
537
|
+
}
|
|
538
|
+
|
|
448
539
|
// hooks/useSessionTimeout.ts
|
|
449
540
|
import { useEffect, useState, useCallback, useRef } from "react";
|
|
450
541
|
function useSessionTimeout(options = {}) {
|
|
@@ -593,10 +684,13 @@ export {
|
|
|
593
684
|
getStoredToken,
|
|
594
685
|
getTimeUntilExpiry,
|
|
595
686
|
getTokenInfo,
|
|
687
|
+
initializeAuth,
|
|
688
|
+
isAuthenticated,
|
|
596
689
|
isTokenExpired,
|
|
597
690
|
resetSessionManager,
|
|
598
691
|
storeRefreshToken,
|
|
599
692
|
storeToken,
|
|
693
|
+
triggerAuthChange,
|
|
600
694
|
useSessionTimeout,
|
|
601
695
|
validateToken
|
|
602
696
|
};
|
package/package.json
CHANGED