Session timeout microfrontend: configurable JWT expiry decoding and refresh with idle tracking
npm install formreader-session-timeoutA lightweight, fully configurable React microfrontend for JWT token refresh management, idle session tracking, and auto-logout with comprehensive event callbacks.
- ✅ JWT Expiry Decoding — Reads token expiry from JWT exp claim, no server roundtrip needed
- ✅ Configurable Refresh Timing — Schedule token refresh at any point before expiry
- ✅ Idle Detection — Automatic idle timeout with configurable warning dialogs
- ✅ Custom Payload Formatting — Tailor refresh/logout request payloads to your API
- ✅ Flexible HTTP Integration — Use your own axios/fetch client or rely on built-in fetch
- ✅ Event-Driven — Full control via callbacks: onRefreshSuccess, onIdle, onSessionExpired, etc.
- ✅ Zero External Dependencies — Works standalone; React is a peer dependency only
- ✅ Fully Typed — TypeScript support out of the box
- ✅ Singleton Pattern — Global session manager or per-component hooks
---
``bash`
npm install @formreader/session-timeout
Or using yarn:
`bash`
yarn add @formreader/session-timeout
---
Import and use the useSessionTimeout hook in any React component:
`typescript
import React from 'react';
import { useSessionTimeout } from '@formreader/session-timeout';
export function MyComponent() {
const {
sessionState,
timeUntilIdle,
idleWarningVisible,
extendSession,
refreshToken,
logout,
} = useSessionTimeout({
enabled: true,
config: {
refreshThresholdMs: 2 60 1000, // Refresh 2 min before expiry
idleTimeoutMs: 15 60 1000, // Logout after 15 min idle
idleCheckIntervalMs: 10 * 1000, // Check idle every 10 sec
idleWarningThresholdMs: 2 60 1000, // Show warning 2 min before idle
autoRefresh: true,
showIdleWarning: true,
debug: true,
// Your API endpoints
refreshEndpoint: '/api/auth/refresh/',
logoutEndpoint: '/api/auth/logout/',
// Custom payload format (if needed)
refreshPayloadFormatter: (token) => ({ refresh: token }),
},
onRefreshSuccess: () => console.log('Token refreshed'),
onIdle: () => console.log('User idle'),
onSessionExpired: () => console.log('Session expired'),
});
return (
Session: {sessionState.isActive ? '🟢 Active' : '🔴 Inactive'}
Your session is about to expire in {timeUntilIdle}ms
$3
Use
SessionManager directly for more control:`typescript
import {
getSessionManager,
resetSessionManager,
getStoredToken,
getTokenInfo,
} from '@formreader/session-timeout';// Initialize on app startup
const manager = getSessionManager({
refreshThresholdMs: 2 60 1000,
idleTimeoutMs: 15 60 1000,
autoRefresh: true,
debug: true,
refreshEndpoint: '/api/auth/refresh/',
logoutEndpoint: '/api/auth/logout/',
refreshPayloadFormatter: (token) => ({ refresh: token }),
});
manager.init();
// Listen to events
manager.on('tokenRefreshed', () => console.log('Token refreshed'));
manager.on('idle', () => console.log('User idle'));
// Manual refresh if needed
await manager.refreshToken();
// Cleanup on logout or unmount
manager.destroy();
`---
Configuration
All settings are optional and inherit sensible defaults. Pass them via the
config object:$3
| Option | Type | Default | Description |
|--------|------|---------|-------------|
|
refreshThresholdMs | number | 2 60 1000 | Milliseconds before token expiry to trigger refresh |
| idleTimeoutMs | number | 15 60 1000 | Milliseconds of inactivity before session ends |
| idleCheckIntervalMs | number | 10 * 1000 | How often to check for idle activity |
| idleWarningThresholdMs | number | 2 60 1000 | Milliseconds before idle timeout to show warning |
| maxSessionDurationMs | number | 8 60 60 * 1000 | Absolute max session duration (8 hours) |$3
| Option | Type | Default | Description |
|--------|------|---------|-------------|
|
refreshEndpoint | string | /auth/refresh/ | URL for token refresh |
| logoutEndpoint | string | /auth/logout/ | URL for logout |
| autoRefresh | boolean | true | Auto-refresh tokens before expiry |$3
| Option | Type | Default | Description |
|--------|------|---------|-------------|
|
showIdleWarning | boolean | true | Show idle warning dialog |
| debug | boolean | false | Log debug messages to console |$3
| Option | Type | Description |
|--------|------|-------------|
|
httpClient? | { post(...): Promise } | Custom HTTP client (defaults to fetch) |
| refreshPayloadFormatter? | (token) => object | Format refresh request payload |
| logoutPayloadFormatter? | (token) => object | Format logout request payload |---
Custom HTTP Client
If you have an existing axios instance or custom HTTP client, pass it to avoid dependencies:
`typescript
import axios from 'axios';const { useSessionTimeout } = require('@formreader/session-timeout');
useSessionTimeout({
config: {
httpClient: {
post: (url, body, options) => axios.post(url, body, options),
},
refreshThresholdMs: 2 60 1000,
// ... other config
},
});
`---
Custom Payload Formatting
Your API may expect a different payload structure. Use the formatters to customize:
$3
`typescript
useSessionTimeout({
config: {
refreshPayloadFormatter: (token) => ({
refresh: token, // API expects "refresh", not "token"
}),
logoutPayloadFormatter: (token) => ({
refresh: token,
}),
},
});
`Request sent:
`json
POST /api/auth/refresh/
{ "refresh": "eyJhbGc..." }
`$3
`typescript
useSessionTimeout({
config: {
refreshPayloadFormatter: (token) => ({
action: 'refresh',
credentials: {
refresh_token: token,
client_id: 'my-client',
},
}),
},
});
`Request sent:
`json
POST /api/auth/refresh/
{
"action": "refresh",
"credentials": {
"refresh_token": "eyJhbGc...",
"client_id": "my-client"
}
}
`---
Event Callbacks
Full control over session lifecycle:
`typescript
useSessionTimeout({
config: { / ... / },
// Called when token is about to expire
onSessionExpiring: () => {
console.warn('Token expiring soon');
}, // Called when user becomes idle
onIdle: () => {
console.log('User idle – logging out');
},
// Called when session has completely expired
onSessionExpired: () => {
console.log('Session expired – redirecting to login');
window.location.href = '/login';
},
// Called after successful token refresh
onRefreshSuccess: () => {
console.log('Token refreshed silently');
},
// Called on refresh failure
onRefreshFailure: (error) => {
console.error('Refresh failed:', error.message);
},
});
`---
Token Storage
Tokens are stored in
sessionStorage by default (cleared on browser close). To persist across tabs, use localStorage:`typescript
import { storeToken, getStoredToken } from '@formreader/session-timeout';// Store persistently
storeToken(token, true); // true = use localStorage
// Retrieve (checks both storage types)
const token = getStoredToken();
`---
Token Inspection
Decode and inspect JWT payloads without verification (client-side only):
`typescript
import { getTokenInfo, isTokenExpired, getTimeUntilExpiry } from '@formreader/session-timeout';const token = getStoredToken();
// Get full token info
const info = getTokenInfo(token);
console.log(info.expiresAt); // Unix timestamp (ms)
console.log(info.expiresIn); // Milliseconds until expiry
console.log(info.payload); // JWT payload object
// Quick checks
const expired = isTokenExpired(token);
const timeLeft = getTimeUntilExpiry(token);
`---
Global Session Manager
For app-wide state, initialize the singleton once at startup:
`typescript
import { getSessionManager, resetSessionManager } from '@formreader/session-timeout';// App startup
const manager = getSessionManager({
refreshThresholdMs: 2 60 1000,
idleTimeoutMs: 15 60 1000,
autoRefresh: true,
refreshEndpoint: '/api/auth/refresh/',
logoutEndpoint: '/api/auth/logout/',
});
manager.init();
// Listen to events
manager.on('tokenRefreshed', () => console.log('Token refreshed'));
// Later, reset if needed (e.g., on logout)
resetSessionManager();
`---
TypeScript Support
Full TypeScript definitions included:
`typescript
import {
SessionConfig,
SessionState,
TokenInfo,
JWTPayload,
RefreshTokenResponse,
UseSessionTimeoutOptions,
} from '@formreader/session-timeout';const config: SessionConfig = {
refreshThresholdMs: 2 60 1000,
idleTimeoutMs: 15 60 1000,
// ... rest of config
};
`---
API Reference
$3
React hook for session management in components.
Parameters:
-
options.enabled?: boolean — Enable/disable the hook (default: true)
- options.config?: Partial — Configuration (merged with defaults)
- options.onSessionExpiring?: () => void — Callback before expiry
- options.onSessionExpired?: () => void — Callback on expiry
- options.onIdle?: () => void — Callback on idle
- options.onRefreshSuccess?: () => void — Callback on refresh success
- options.onRefreshFailure?: (error: Error) => void — Callback on refresh failureReturns:
`typescript
{
sessionState: SessionState; // Current session state
timeUntilIdle: number | null; // Milliseconds until idle
idleWarningVisible: boolean; // Show idle warning
extendSession: () => void; // Reset idle timer
refreshToken: () => Promise; // Manually refresh
logout: () => Promise; // Logout
updateConfig: (newConfig) => void; // Update config
manager: SessionManager; // Underlying manager
}
`$3
Direct access to session management service.
Methods:
-
init() — Initialize session management
- refreshToken(): Promise — Refresh token
- logout(): Promise — Logout and cleanup
- extendSession() — Reset idle timer
- getState(): SessionState — Current state
- getConfig(): SessionConfig — Current config
- updateConfig(newConfig) — Update config
- on(event, callback): () => void — Subscribe to events
- destroy() — Cleanup and destroy managerEvents:
-
'initialized' — Manager initialized
- 'tokenRefreshed' — Token successfully refreshed
- 'idle' — User became idle
- 'activity' — User activity detected
- 'idleWarning' — Idle warning (includes timeRemaining)
- 'sessionExtended' — Session extended
- 'refreshFailed' — Token refresh failed
- 'loggedOut' — Logged out$3
-
getTokenInfo(token): TokenInfo | null — Get token expiry and payload
- isTokenExpired(token, bufferMs?): boolean — Check if token expired
- getTimeUntilExpiry(token): number — Get milliseconds until expiry
- getStoredToken(): string | null — Get token from storage
- storeToken(token, persistent?) — Store token
- clearToken() — Clear stored token
- validateToken(token) — Validate token structure---
Production Checklist
- [ ] Configure
refreshThresholdMs for your token lifetime
- [ ] Set refreshEndpoint to your backend refresh URL
- [ ] Customize refreshPayloadFormatter if your API requires custom payload
- [ ] Set appropriate idleTimeoutMs based on security requirements
- [ ] Pass your app's HTTP client via httpClient option
- [ ] Test token refresh before token expires
- [ ] Test idle timeout and warning
- [ ] Handle onSessionExpired to redirect to login
- [ ] Disable debug: true in production
- [ ] Monitor onRefreshFailure for refresh failures---
Browser Support
- Chrome/Edge: ✅ All versions
- Firefox: ✅ All versions
- Safari: ✅ 12+
- Mobile: ✅ iOS 12+, Android 5+
Requires
fetch` API or polyfill.---
MIT