formreader-session-timeout 0.2.0
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/README.md +459 -0
- package/dist/index.d.ts +216 -0
- package/dist/index.js +590 -0
- package/dist/index.mjs +553 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
# @formreader/session-timeout
|
|
2
|
+
|
|
3
|
+
A lightweight, fully configurable React microfrontend for **JWT token refresh management**, **idle session tracking**, and **auto-logout** with comprehensive event callbacks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **JWT Expiry Decoding** — Reads token expiry from JWT `exp` claim, no server roundtrip needed
|
|
8
|
+
- ✅ **Configurable Refresh Timing** — Schedule token refresh at any point before expiry
|
|
9
|
+
- ✅ **Idle Detection** — Automatic idle timeout with configurable warning dialogs
|
|
10
|
+
- ✅ **Custom Payload Formatting** — Tailor refresh/logout request payloads to your API
|
|
11
|
+
- ✅ **Flexible HTTP Integration** — Use your own axios/fetch client or rely on built-in fetch
|
|
12
|
+
- ✅ **Event-Driven** — Full control via callbacks: `onRefreshSuccess`, `onIdle`, `onSessionExpired`, etc.
|
|
13
|
+
- ✅ **Zero External Dependencies** — Works standalone; React is a peer dependency only
|
|
14
|
+
- ✅ **Fully Typed** — TypeScript support out of the box
|
|
15
|
+
- ✅ **Singleton Pattern** — Global session manager or per-component hooks
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @formreader/session-timeout
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or using yarn:
|
|
26
|
+
```bash
|
|
27
|
+
yarn add @formreader/session-timeout
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### 1. Hook-Based Usage (Recommended)
|
|
35
|
+
|
|
36
|
+
Import and use the `useSessionTimeout` hook in any React component:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import React from 'react';
|
|
40
|
+
import { useSessionTimeout } from '@formreader/session-timeout';
|
|
41
|
+
|
|
42
|
+
export function MyComponent() {
|
|
43
|
+
const {
|
|
44
|
+
sessionState,
|
|
45
|
+
timeUntilIdle,
|
|
46
|
+
idleWarningVisible,
|
|
47
|
+
extendSession,
|
|
48
|
+
refreshToken,
|
|
49
|
+
logout,
|
|
50
|
+
} = useSessionTimeout({
|
|
51
|
+
enabled: true,
|
|
52
|
+
config: {
|
|
53
|
+
refreshThresholdMs: 2 * 60 * 1000, // Refresh 2 min before expiry
|
|
54
|
+
idleTimeoutMs: 15 * 60 * 1000, // Logout after 15 min idle
|
|
55
|
+
idleCheckIntervalMs: 10 * 1000, // Check idle every 10 sec
|
|
56
|
+
idleWarningThresholdMs: 2 * 60 * 1000, // Show warning 2 min before idle
|
|
57
|
+
autoRefresh: true,
|
|
58
|
+
showIdleWarning: true,
|
|
59
|
+
debug: true,
|
|
60
|
+
// Your API endpoints
|
|
61
|
+
refreshEndpoint: '/api/auth/refresh/',
|
|
62
|
+
logoutEndpoint: '/api/auth/logout/',
|
|
63
|
+
// Custom payload format (if needed)
|
|
64
|
+
refreshPayloadFormatter: (token) => ({ refresh: token }),
|
|
65
|
+
},
|
|
66
|
+
onRefreshSuccess: () => console.log('Token refreshed'),
|
|
67
|
+
onIdle: () => console.log('User idle'),
|
|
68
|
+
onSessionExpired: () => console.log('Session expired'),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div>
|
|
73
|
+
<p>Session: {sessionState.isActive ? '🟢 Active' : '🔴 Inactive'}</p>
|
|
74
|
+
{idleWarningVisible && (
|
|
75
|
+
<div className="warning">
|
|
76
|
+
<p>Your session is about to expire in {timeUntilIdle}ms</p>
|
|
77
|
+
<button onClick={extendSession}>Stay Logged In</button>
|
|
78
|
+
</div>
|
|
79
|
+
)}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. Service-Based Usage
|
|
86
|
+
|
|
87
|
+
Use `SessionManager` directly for more control:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import {
|
|
91
|
+
getSessionManager,
|
|
92
|
+
resetSessionManager,
|
|
93
|
+
getStoredToken,
|
|
94
|
+
getTokenInfo,
|
|
95
|
+
} from '@formreader/session-timeout';
|
|
96
|
+
|
|
97
|
+
// Initialize on app startup
|
|
98
|
+
const manager = getSessionManager({
|
|
99
|
+
refreshThresholdMs: 2 * 60 * 1000,
|
|
100
|
+
idleTimeoutMs: 15 * 60 * 1000,
|
|
101
|
+
autoRefresh: true,
|
|
102
|
+
debug: true,
|
|
103
|
+
refreshEndpoint: '/api/auth/refresh/',
|
|
104
|
+
logoutEndpoint: '/api/auth/logout/',
|
|
105
|
+
refreshPayloadFormatter: (token) => ({ refresh: token }),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
manager.init();
|
|
109
|
+
|
|
110
|
+
// Listen to events
|
|
111
|
+
manager.on('tokenRefreshed', () => console.log('Token refreshed'));
|
|
112
|
+
manager.on('idle', () => console.log('User idle'));
|
|
113
|
+
|
|
114
|
+
// Manual refresh if needed
|
|
115
|
+
await manager.refreshToken();
|
|
116
|
+
|
|
117
|
+
// Cleanup on logout or unmount
|
|
118
|
+
manager.destroy();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Configuration
|
|
124
|
+
|
|
125
|
+
All settings are optional and inherit sensible defaults. Pass them via the `config` object:
|
|
126
|
+
|
|
127
|
+
### Session Timing
|
|
128
|
+
|
|
129
|
+
| Option | Type | Default | Description |
|
|
130
|
+
|--------|------|---------|-------------|
|
|
131
|
+
| `refreshThresholdMs` | number | `2 * 60 * 1000` | Milliseconds before token expiry to trigger refresh |
|
|
132
|
+
| `idleTimeoutMs` | number | `15 * 60 * 1000` | Milliseconds of inactivity before session ends |
|
|
133
|
+
| `idleCheckIntervalMs` | number | `10 * 1000` | How often to check for idle activity |
|
|
134
|
+
| `idleWarningThresholdMs` | number | `2 * 60 * 1000` | Milliseconds before idle timeout to show warning |
|
|
135
|
+
| `maxSessionDurationMs` | number | `8 * 60 * 60 * 1000` | Absolute max session duration (8 hours) |
|
|
136
|
+
|
|
137
|
+
### API Configuration
|
|
138
|
+
|
|
139
|
+
| Option | Type | Default | Description |
|
|
140
|
+
|--------|------|---------|-------------|
|
|
141
|
+
| `refreshEndpoint` | string | `/auth/refresh/` | URL for token refresh |
|
|
142
|
+
| `logoutEndpoint` | string | `/auth/logout/` | URL for logout |
|
|
143
|
+
| `autoRefresh` | boolean | `true` | Auto-refresh tokens before expiry |
|
|
144
|
+
|
|
145
|
+
### UI Configuration
|
|
146
|
+
|
|
147
|
+
| Option | Type | Default | Description |
|
|
148
|
+
|--------|------|---------|-------------|
|
|
149
|
+
| `showIdleWarning` | boolean | `true` | Show idle warning dialog |
|
|
150
|
+
| `debug` | boolean | `false` | Log debug messages to console |
|
|
151
|
+
|
|
152
|
+
### Custom Integration
|
|
153
|
+
|
|
154
|
+
| Option | Type | Description |
|
|
155
|
+
|--------|------|-------------|
|
|
156
|
+
| `httpClient?` | `{ post(...): Promise }` | Custom HTTP client (defaults to `fetch`) |
|
|
157
|
+
| `refreshPayloadFormatter?` | `(token) => object` | Format refresh request payload |
|
|
158
|
+
| `logoutPayloadFormatter?` | `(token) => object` | Format logout request payload |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Custom HTTP Client
|
|
163
|
+
|
|
164
|
+
If you have an existing axios instance or custom HTTP client, pass it to avoid dependencies:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import axios from 'axios';
|
|
168
|
+
|
|
169
|
+
const { useSessionTimeout } = require('@formreader/session-timeout');
|
|
170
|
+
|
|
171
|
+
useSessionTimeout({
|
|
172
|
+
config: {
|
|
173
|
+
httpClient: {
|
|
174
|
+
post: (url, body, options) => axios.post(url, body, options),
|
|
175
|
+
},
|
|
176
|
+
refreshThresholdMs: 2 * 60 * 1000,
|
|
177
|
+
// ... other config
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Custom Payload Formatting
|
|
185
|
+
|
|
186
|
+
Your API may expect a different payload structure. Use the formatters to customize:
|
|
187
|
+
|
|
188
|
+
### Example 1: API requires `refresh` field
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
useSessionTimeout({
|
|
192
|
+
config: {
|
|
193
|
+
refreshPayloadFormatter: (token) => ({
|
|
194
|
+
refresh: token, // API expects "refresh", not "token"
|
|
195
|
+
}),
|
|
196
|
+
logoutPayloadFormatter: (token) => ({
|
|
197
|
+
refresh: token,
|
|
198
|
+
}),
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Request sent:**
|
|
204
|
+
```json
|
|
205
|
+
POST /api/auth/refresh/
|
|
206
|
+
{ "refresh": "eyJhbGc..." }
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Example 2: Complex nested structure
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
useSessionTimeout({
|
|
213
|
+
config: {
|
|
214
|
+
refreshPayloadFormatter: (token) => ({
|
|
215
|
+
action: 'refresh',
|
|
216
|
+
credentials: {
|
|
217
|
+
refresh_token: token,
|
|
218
|
+
client_id: 'my-client',
|
|
219
|
+
},
|
|
220
|
+
}),
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Request sent:**
|
|
226
|
+
```json
|
|
227
|
+
POST /api/auth/refresh/
|
|
228
|
+
{
|
|
229
|
+
"action": "refresh",
|
|
230
|
+
"credentials": {
|
|
231
|
+
"refresh_token": "eyJhbGc...",
|
|
232
|
+
"client_id": "my-client"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Event Callbacks
|
|
240
|
+
|
|
241
|
+
Full control over session lifecycle:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
useSessionTimeout({
|
|
245
|
+
config: { /* ... */ },
|
|
246
|
+
|
|
247
|
+
// Called when token is about to expire
|
|
248
|
+
onSessionExpiring: () => {
|
|
249
|
+
console.warn('Token expiring soon');
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
// Called when user becomes idle
|
|
253
|
+
onIdle: () => {
|
|
254
|
+
console.log('User idle – logging out');
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
// Called when session has completely expired
|
|
258
|
+
onSessionExpired: () => {
|
|
259
|
+
console.log('Session expired – redirecting to login');
|
|
260
|
+
window.location.href = '/login';
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
// Called after successful token refresh
|
|
264
|
+
onRefreshSuccess: () => {
|
|
265
|
+
console.log('Token refreshed silently');
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
// Called on refresh failure
|
|
269
|
+
onRefreshFailure: (error) => {
|
|
270
|
+
console.error('Refresh failed:', error.message);
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Token Storage
|
|
278
|
+
|
|
279
|
+
Tokens are stored in `sessionStorage` by default (cleared on browser close). To persist across tabs, use `localStorage`:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
import { storeToken, getStoredToken } from '@formreader/session-timeout';
|
|
283
|
+
|
|
284
|
+
// Store persistently
|
|
285
|
+
storeToken(token, true); // true = use localStorage
|
|
286
|
+
|
|
287
|
+
// Retrieve (checks both storage types)
|
|
288
|
+
const token = getStoredToken();
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Token Inspection
|
|
294
|
+
|
|
295
|
+
Decode and inspect JWT payloads without verification (client-side only):
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { getTokenInfo, isTokenExpired, getTimeUntilExpiry } from '@formreader/session-timeout';
|
|
299
|
+
|
|
300
|
+
const token = getStoredToken();
|
|
301
|
+
|
|
302
|
+
// Get full token info
|
|
303
|
+
const info = getTokenInfo(token);
|
|
304
|
+
console.log(info.expiresAt); // Unix timestamp (ms)
|
|
305
|
+
console.log(info.expiresIn); // Milliseconds until expiry
|
|
306
|
+
console.log(info.payload); // JWT payload object
|
|
307
|
+
|
|
308
|
+
// Quick checks
|
|
309
|
+
const expired = isTokenExpired(token);
|
|
310
|
+
const timeLeft = getTimeUntilExpiry(token);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Global Session Manager
|
|
316
|
+
|
|
317
|
+
For app-wide state, initialize the singleton once at startup:
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { getSessionManager, resetSessionManager } from '@formreader/session-timeout';
|
|
321
|
+
|
|
322
|
+
// App startup
|
|
323
|
+
const manager = getSessionManager({
|
|
324
|
+
refreshThresholdMs: 2 * 60 * 1000,
|
|
325
|
+
idleTimeoutMs: 15 * 60 * 1000,
|
|
326
|
+
autoRefresh: true,
|
|
327
|
+
refreshEndpoint: '/api/auth/refresh/',
|
|
328
|
+
logoutEndpoint: '/api/auth/logout/',
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
manager.init();
|
|
332
|
+
|
|
333
|
+
// Listen to events
|
|
334
|
+
manager.on('tokenRefreshed', () => console.log('Token refreshed'));
|
|
335
|
+
|
|
336
|
+
// Later, reset if needed (e.g., on logout)
|
|
337
|
+
resetSessionManager();
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## TypeScript Support
|
|
343
|
+
|
|
344
|
+
Full TypeScript definitions included:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import {
|
|
348
|
+
SessionConfig,
|
|
349
|
+
SessionState,
|
|
350
|
+
TokenInfo,
|
|
351
|
+
JWTPayload,
|
|
352
|
+
RefreshTokenResponse,
|
|
353
|
+
UseSessionTimeoutOptions,
|
|
354
|
+
} from '@formreader/session-timeout';
|
|
355
|
+
|
|
356
|
+
const config: SessionConfig = {
|
|
357
|
+
refreshThresholdMs: 2 * 60 * 1000,
|
|
358
|
+
idleTimeoutMs: 15 * 60 * 1000,
|
|
359
|
+
// ... rest of config
|
|
360
|
+
};
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## API Reference
|
|
366
|
+
|
|
367
|
+
### `useSessionTimeout(options?)`
|
|
368
|
+
|
|
369
|
+
React hook for session management in components.
|
|
370
|
+
|
|
371
|
+
**Parameters:**
|
|
372
|
+
- `options.enabled?: boolean` — Enable/disable the hook (default: `true`)
|
|
373
|
+
- `options.config?: Partial<SessionConfig>` — Configuration (merged with defaults)
|
|
374
|
+
- `options.onSessionExpiring?: () => void` — Callback before expiry
|
|
375
|
+
- `options.onSessionExpired?: () => void` — Callback on expiry
|
|
376
|
+
- `options.onIdle?: () => void` — Callback on idle
|
|
377
|
+
- `options.onRefreshSuccess?: () => void` — Callback on refresh success
|
|
378
|
+
- `options.onRefreshFailure?: (error: Error) => void` — Callback on refresh failure
|
|
379
|
+
|
|
380
|
+
**Returns:**
|
|
381
|
+
```typescript
|
|
382
|
+
{
|
|
383
|
+
sessionState: SessionState; // Current session state
|
|
384
|
+
timeUntilIdle: number | null; // Milliseconds until idle
|
|
385
|
+
idleWarningVisible: boolean; // Show idle warning
|
|
386
|
+
extendSession: () => void; // Reset idle timer
|
|
387
|
+
refreshToken: () => Promise<boolean>; // Manually refresh
|
|
388
|
+
logout: () => Promise<void>; // Logout
|
|
389
|
+
updateConfig: (newConfig) => void; // Update config
|
|
390
|
+
manager: SessionManager; // Underlying manager
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### `SessionManager`
|
|
395
|
+
|
|
396
|
+
Direct access to session management service.
|
|
397
|
+
|
|
398
|
+
**Methods:**
|
|
399
|
+
- `init()` — Initialize session management
|
|
400
|
+
- `refreshToken(): Promise<boolean>` — Refresh token
|
|
401
|
+
- `logout(): Promise<void>` — Logout and cleanup
|
|
402
|
+
- `extendSession()` — Reset idle timer
|
|
403
|
+
- `getState(): SessionState` — Current state
|
|
404
|
+
- `getConfig(): SessionConfig` — Current config
|
|
405
|
+
- `updateConfig(newConfig)` — Update config
|
|
406
|
+
- `on(event, callback): () => void` — Subscribe to events
|
|
407
|
+
- `destroy()` — Cleanup and destroy manager
|
|
408
|
+
|
|
409
|
+
**Events:**
|
|
410
|
+
- `'initialized'` — Manager initialized
|
|
411
|
+
- `'tokenRefreshed'` — Token successfully refreshed
|
|
412
|
+
- `'idle'` — User became idle
|
|
413
|
+
- `'activity'` — User activity detected
|
|
414
|
+
- `'idleWarning'` — Idle warning (includes `timeRemaining`)
|
|
415
|
+
- `'sessionExtended'` — Session extended
|
|
416
|
+
- `'refreshFailed'` — Token refresh failed
|
|
417
|
+
- `'loggedOut'` — Logged out
|
|
418
|
+
|
|
419
|
+
### Token Service Functions
|
|
420
|
+
|
|
421
|
+
- `getTokenInfo(token): TokenInfo | null` — Get token expiry and payload
|
|
422
|
+
- `isTokenExpired(token, bufferMs?): boolean` — Check if token expired
|
|
423
|
+
- `getTimeUntilExpiry(token): number` — Get milliseconds until expiry
|
|
424
|
+
- `getStoredToken(): string | null` — Get token from storage
|
|
425
|
+
- `storeToken(token, persistent?)` — Store token
|
|
426
|
+
- `clearToken()` — Clear stored token
|
|
427
|
+
- `validateToken(token)` — Validate token structure
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Production Checklist
|
|
432
|
+
|
|
433
|
+
- [ ] Configure `refreshThresholdMs` for your token lifetime
|
|
434
|
+
- [ ] Set `refreshEndpoint` to your backend refresh URL
|
|
435
|
+
- [ ] Customize `refreshPayloadFormatter` if your API requires custom payload
|
|
436
|
+
- [ ] Set appropriate `idleTimeoutMs` based on security requirements
|
|
437
|
+
- [ ] Pass your app's HTTP client via `httpClient` option
|
|
438
|
+
- [ ] Test token refresh before token expires
|
|
439
|
+
- [ ] Test idle timeout and warning
|
|
440
|
+
- [ ] Handle `onSessionExpired` to redirect to login
|
|
441
|
+
- [ ] Disable `debug: true` in production
|
|
442
|
+
- [ ] Monitor `onRefreshFailure` for refresh failures
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Browser Support
|
|
447
|
+
|
|
448
|
+
- Chrome/Edge: ✅ All versions
|
|
449
|
+
- Firefox: ✅ All versions
|
|
450
|
+
- Safari: ✅ 12+
|
|
451
|
+
- Mobile: ✅ iOS 12+, Android 5+
|
|
452
|
+
|
|
453
|
+
Requires `fetch` API or polyfill.
|
|
454
|
+
|
|
455
|
+
---
|
|
456
|
+
|
|
457
|
+
## License
|
|
458
|
+
|
|
459
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Timeout Micro Frontend Types
|
|
3
|
+
* Configurable, reusable types for multi-application token refresh management
|
|
4
|
+
*/
|
|
5
|
+
interface SessionConfig {
|
|
6
|
+
/** Time before token expiry to trigger refresh (milliseconds) */
|
|
7
|
+
refreshThresholdMs: number;
|
|
8
|
+
/** Interval to check for idle activity (milliseconds) */
|
|
9
|
+
idleCheckIntervalMs: number;
|
|
10
|
+
/** Time of inactivity before session expires (milliseconds) */
|
|
11
|
+
idleTimeoutMs: number;
|
|
12
|
+
/** Maximum session duration regardless of activity (milliseconds) */
|
|
13
|
+
maxSessionDurationMs: number;
|
|
14
|
+
/** Endpoint to call for token refresh */
|
|
15
|
+
refreshEndpoint: string;
|
|
16
|
+
/** Endpoint to call for logout */
|
|
17
|
+
logoutEndpoint: string;
|
|
18
|
+
/** Whether to show idle warning dialog */
|
|
19
|
+
showIdleWarning: boolean;
|
|
20
|
+
/** Time before idle timeout to show warning (milliseconds) */
|
|
21
|
+
idleWarningThresholdMs: number;
|
|
22
|
+
/** Callback when session is about to expire */
|
|
23
|
+
onSessionExpiring?: () => void;
|
|
24
|
+
/** Callback when user is idle */
|
|
25
|
+
onIdle?: () => void;
|
|
26
|
+
/** Callback when session has expired */
|
|
27
|
+
onSessionExpired?: () => void;
|
|
28
|
+
/** Callback on refresh success */
|
|
29
|
+
onRefreshSuccess?: () => void;
|
|
30
|
+
/** Callback on refresh failure */
|
|
31
|
+
onRefreshFailure?: (error: Error) => void;
|
|
32
|
+
/** Whether to auto-refresh before expiry */
|
|
33
|
+
autoRefresh: boolean;
|
|
34
|
+
/** Debug mode for logging */
|
|
35
|
+
debug: boolean;
|
|
36
|
+
/** Optional HTTP client to use for refresh/logout calls. If not provided, will use fetch. */
|
|
37
|
+
httpClient?: {
|
|
38
|
+
post: (url: string, body?: any, options?: any) => Promise<{
|
|
39
|
+
data: any;
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
/** Custom function to format the refresh request payload. Allows you to define exactly what data is sent to your API. */
|
|
43
|
+
refreshPayloadFormatter?: (token: string) => Record<string, any>;
|
|
44
|
+
/** Custom function to format the logout request payload. Allows you to define exactly what data is sent to your API. */
|
|
45
|
+
logoutPayloadFormatter?: (token: string) => Record<string, any>;
|
|
46
|
+
}
|
|
47
|
+
interface JWTPayload {
|
|
48
|
+
exp: number;
|
|
49
|
+
iat: number;
|
|
50
|
+
sub?: string;
|
|
51
|
+
[key: string]: any;
|
|
52
|
+
}
|
|
53
|
+
interface TokenInfo {
|
|
54
|
+
token: string;
|
|
55
|
+
expiresAt: number;
|
|
56
|
+
expiresIn: number;
|
|
57
|
+
payload: JWTPayload;
|
|
58
|
+
}
|
|
59
|
+
interface SessionState {
|
|
60
|
+
isActive: boolean;
|
|
61
|
+
isIdle: boolean;
|
|
62
|
+
tokenExpiry?: number;
|
|
63
|
+
lastActivityTime: number;
|
|
64
|
+
refreshAttempts: number;
|
|
65
|
+
isRefreshing: boolean;
|
|
66
|
+
}
|
|
67
|
+
interface RefreshTokenResponse {
|
|
68
|
+
token: string;
|
|
69
|
+
access_token?: string;
|
|
70
|
+
expiresIn?: number;
|
|
71
|
+
[key: string]: any;
|
|
72
|
+
}
|
|
73
|
+
declare const DEFAULT_SESSION_CONFIG: SessionConfig;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Session Manager Service
|
|
77
|
+
* Manages token refresh, idle tracking, and session lifecycle
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
declare class SessionManager {
|
|
81
|
+
private config;
|
|
82
|
+
private state;
|
|
83
|
+
private refreshTimer;
|
|
84
|
+
private idleTimer;
|
|
85
|
+
private idleCheckTimer;
|
|
86
|
+
private maxSessionTimer;
|
|
87
|
+
private listeners;
|
|
88
|
+
private requestDeduplication;
|
|
89
|
+
constructor(config: Partial<SessionConfig>);
|
|
90
|
+
/**
|
|
91
|
+
* Initialize session management
|
|
92
|
+
*/
|
|
93
|
+
init(): void;
|
|
94
|
+
/**
|
|
95
|
+
* Setup token refresh before expiry
|
|
96
|
+
*/
|
|
97
|
+
private setupTokenRefresh;
|
|
98
|
+
/**
|
|
99
|
+
* Setup idle activity tracking
|
|
100
|
+
*/
|
|
101
|
+
private setupIdleTracking;
|
|
102
|
+
/**
|
|
103
|
+
* Setup max session duration timer
|
|
104
|
+
*/
|
|
105
|
+
private setupMaxSessionDuration;
|
|
106
|
+
/**
|
|
107
|
+
* Refresh token
|
|
108
|
+
*/
|
|
109
|
+
refreshToken(): Promise<boolean>;
|
|
110
|
+
/**
|
|
111
|
+
* Logout and cleanup
|
|
112
|
+
*/
|
|
113
|
+
logout(): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Extend session (reset idle timer)
|
|
116
|
+
*/
|
|
117
|
+
extendSession(): void;
|
|
118
|
+
/**
|
|
119
|
+
* Get current state
|
|
120
|
+
*/
|
|
121
|
+
getState(): SessionState;
|
|
122
|
+
/**
|
|
123
|
+
* Get current config
|
|
124
|
+
*/
|
|
125
|
+
getConfig(): SessionConfig;
|
|
126
|
+
/**
|
|
127
|
+
* Update config
|
|
128
|
+
*/
|
|
129
|
+
updateConfig(newConfig: Partial<SessionConfig>): void;
|
|
130
|
+
/**
|
|
131
|
+
* Event listeners
|
|
132
|
+
*/
|
|
133
|
+
on(event: string, callback: Function): () => void;
|
|
134
|
+
/**
|
|
135
|
+
* Emit event
|
|
136
|
+
*/
|
|
137
|
+
private emit;
|
|
138
|
+
/**
|
|
139
|
+
* Cleanup timers and listeners
|
|
140
|
+
*/
|
|
141
|
+
private cleanup;
|
|
142
|
+
/**
|
|
143
|
+
* Destroy session manager
|
|
144
|
+
*/
|
|
145
|
+
destroy(): void;
|
|
146
|
+
/**
|
|
147
|
+
* Logging utility
|
|
148
|
+
*/
|
|
149
|
+
private log;
|
|
150
|
+
}
|
|
151
|
+
declare function getSessionManager(config?: Partial<SessionConfig>): SessionManager;
|
|
152
|
+
declare function resetSessionManager(): void;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Token Service
|
|
156
|
+
* Handles JWT token parsing, decoding, and expiry calculations
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get token info including expiry time
|
|
161
|
+
*/
|
|
162
|
+
declare function getTokenInfo(token: string): TokenInfo | null;
|
|
163
|
+
/**
|
|
164
|
+
* Check if token is expired
|
|
165
|
+
*/
|
|
166
|
+
declare function isTokenExpired(token: string, bufferMs?: number): boolean;
|
|
167
|
+
/**
|
|
168
|
+
* Get remaining time until token expiry
|
|
169
|
+
*/
|
|
170
|
+
declare function getTimeUntilExpiry(token: string): number;
|
|
171
|
+
/**
|
|
172
|
+
* Extract token from storage
|
|
173
|
+
*/
|
|
174
|
+
declare function getStoredToken(): string | null;
|
|
175
|
+
/**
|
|
176
|
+
* Store token in appropriate storage
|
|
177
|
+
*/
|
|
178
|
+
declare function storeToken(token: string, persistent?: boolean): void;
|
|
179
|
+
/**
|
|
180
|
+
* Clear stored token
|
|
181
|
+
*/
|
|
182
|
+
declare function clearToken(): void;
|
|
183
|
+
/**
|
|
184
|
+
* Validate token structure and expiry
|
|
185
|
+
*/
|
|
186
|
+
declare function validateToken(token: string): {
|
|
187
|
+
valid: boolean;
|
|
188
|
+
error?: string;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* useSessionTimeout Hook
|
|
193
|
+
* React hook for session timeout management in components
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
interface UseSessionTimeoutOptions {
|
|
197
|
+
config?: Partial<SessionConfig>;
|
|
198
|
+
enabled?: boolean;
|
|
199
|
+
onSessionExpiring?: () => void;
|
|
200
|
+
onSessionExpired?: () => void;
|
|
201
|
+
onIdle?: () => void;
|
|
202
|
+
onRefreshSuccess?: () => void;
|
|
203
|
+
}
|
|
204
|
+
declare function useSessionTimeout(options?: UseSessionTimeoutOptions): {
|
|
205
|
+
sessionState: SessionState;
|
|
206
|
+
timeUntilExpiry: any;
|
|
207
|
+
timeUntilIdle: number;
|
|
208
|
+
idleWarningVisible: boolean;
|
|
209
|
+
extendSession: () => void;
|
|
210
|
+
refreshToken: () => Promise<boolean>;
|
|
211
|
+
logout: () => Promise<void>;
|
|
212
|
+
updateConfig: (newConfig: Partial<SessionConfig>) => void;
|
|
213
|
+
manager: SessionManager;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export { DEFAULT_SESSION_CONFIG, JWTPayload, RefreshTokenResponse, SessionConfig, SessionManager, SessionState, TokenInfo, UseSessionTimeoutOptions, clearToken, getSessionManager, getStoredToken, getTimeUntilExpiry, getTokenInfo, isTokenExpired, resetSessionManager, storeToken, useSessionTimeout, validateToken };
|