npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sauravart/fgs-session-management

v1.1.4

Published

Angular session management library with timeout handling, activity tracking, multi-session conflict detection, cross-tab synchronization, network status handling, session lock/unlock, and UI components

Readme

FGS Session Management

A comprehensive Angular session management library with timeout handling, activity tracking, multi-session conflict detection, cross-tab synchronization, network status handling, session lock/unlock, and beautiful UI components.

npm version License: MIT

Features

  • Session Timeout Management - Automatic session expiry with configurable timeout and warning countdown
  • Activity Tracking - Track user activity (mouse, keyboard, scroll, touch, visibility)
  • Warning Dialog - Beautiful countdown dialog before session expires
  • Multi-Session Detection - Detect and handle multiple active sessions across devices
  • Cross-Tab Synchronization - Sync session state across browser tabs using BroadcastChannel API
  • Network Status Handling - Detect online/offline status and handle reconnection gracefully
  • Session Lock/Unlock - Lock sessions for security with optional password protection
  • Proactive Session Refresh - Automatically refresh sessions before expiry
  • Error Recovery - Automatic retry with exponential backoff for session creation
  • Route Guards - Protect routes with authentication, role, and permission guards
  • HTTP Interceptor - Automatic token injection and 401/403 handling
  • Device Fingerprinting - Track sessions with unique device identification
  • IP Geolocation - Optional IP-based location tracking
  • Fully Customizable - Override UI components, callbacks, and behavior

Installation

npm install @sauravart/fgs-session-management

Requirements

  • Angular 17, 18, or 19
  • RxJS 7.x

Quick Start

1. Configure the Provider

In your app.config.ts:

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideFgsSessionWithInterceptor } from '@sauravart/fgs-session-management';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideFgsSessionWithInterceptor({
      apiBaseUrl: 'http://localhost:3000/api',  // Your API base URL
      endpoints: {
        createSession: '/session/create',
        validateSession: '/session/validate',
        refreshSession: '/session/refresh',
        revokeSession: '/session/revoke',
        listSessions: '/session/list',
        logout: '/auth/logout',
      },
      sessionTimeoutMs: 300000, // 5 minutes (should match API config)
      warningWindowSeconds: 60, // Show warning 60 seconds before expiry
    }),
  ],
};

2. Add UI Components to App Component

In your app.component.ts:

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import {
  FgsSessionTimeoutDialogComponent,
  FgsSessionConflictModalComponent,
  FgsSessionLockScreenComponent,
} from '@sauravart/fgs-session-management';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    RouterOutlet,
    FgsSessionTimeoutDialogComponent,
    FgsSessionConflictModalComponent,
    FgsSessionLockScreenComponent,
  ],
  template: `
    <router-outlet></router-outlet>

    <!-- Session Management UI Components -->
    <fgs-session-timeout-dialog></fgs-session-timeout-dialog>
    <fgs-session-conflict-modal></fgs-session-conflict-modal>
    <fgs-session-lock-screen></fgs-session-lock-screen>
  `,
})
export class AppComponent {}

3. Initialize Session After Login

In your login component or service:

import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
import { FgsSessionService } from '@sauravart/fgs-session-management';

@Component({
  selector: 'app-login',
  // ...
})
export class LoginComponent {
  private sessionService = inject(FgsSessionService);
  private router = inject(Router);

  async onLoginSuccess(response: any) {
    try {
      // Initialize session after successful login
      await this.sessionService.initializeSession(
        response.userData,    // User data object
        response.authToken,   // Authentication token
        response.userId,      // Optional: User ID
        response.userCode     // Optional: User code
      );

      // Navigate to dashboard
      this.router.navigate(['/dashboard']);
    } catch (error) {
      console.error('Failed to initialize session:', error);
    }
  }
}

4. Protect Routes with Guards

import { Routes } from '@angular/router';
import {
  fgsSessionGuard,
  fgsGuestGuard,
  fgsRoleGuard,
  fgsPermissionGuard,
} from '@sauravart/fgs-session-management';

export const routes: Routes = [
  // Public routes (only accessible when NOT logged in)
  {
    path: 'login',
    component: LoginComponent,
    canActivate: [fgsGuestGuard],
  },

  // Protected routes (require authentication)
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [fgsSessionGuard],
  },

  // Role-based protection
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [fgsSessionGuard, fgsRoleGuard(['admin', 'superadmin'])],
  },

  // Permission-based protection
  {
    path: 'reports',
    component: ReportsComponent,
    canActivate: [fgsSessionGuard, fgsPermissionGuard(['view_reports'])],
  },

  // Permission-based with ALL permissions required
  {
    path: 'settings',
    component: SettingsComponent,
    canActivate: [fgsSessionGuard, fgsPermissionGuard(['read_settings', 'write_settings'], true)],
  },
];

Configuration Options

Full Configuration Example

provideFgsSession({
  // Required: API Configuration
  apiBaseUrl: 'https://your-api.com/api',
  endpoints: {
    createSession: '/session/create',
    validateSession: '/session/validate',
    refreshSession: '/session/refresh',
    revokeSession: '/session/revoke',
    listSessions: '/session/list',
    logout: '/auth/logout',
  },

  // Timing Configuration
  sessionTimeoutMs: 600000,        // 10 minutes (default)
  warningWindowSeconds: 60,        // 60 seconds (default)
  activityThrottleMs: 1000,        // 1 second (default)
  refreshThrottleMs: 30000,        // 30 seconds (default)
  validationThrottleMs: 5000,      // 5 seconds (default)

  // Feature Flags
  features: {
    enableMultiSessionDetection: true,  // Detect multiple active sessions
    enableDeviceFingerprint: true,      // Generate unique device ID
    enableIPGeolocation: true,          // Fetch IP-based location
    enableActivityTracking: true,       // Track user activity
  },

  // UI Configuration
  ui: {
    showTimeoutDialog: true,            // Show timeout warning dialog
    showConflictModal: true,            // Show conflict detection modal
    showLockScreen: true,               // Show lock screen when locked
    dialogTitle: 'Session Expiring',
    dialogMessage: 'Your session is about to expire due to inactivity.',
    dialogExtendButtonText: 'Extend Session',
    dialogLogoutButtonText: 'Logout',
    conflictModalTitle: 'Active Session Detected',
    conflictModalMessage: 'Another session is already active.',
    forceLogoutDelaySeconds: 300,       // 5 minutes before force logout enabled
    lockScreenTitle: 'Session Locked',
    lockScreenMessage: 'Your session has been locked for security.',
  },

  // Route Configuration
  routes: {
    loginRoute: '/login',
    afterLoginRoute: '/dashboard',
  },

  // Storage Keys (customize if needed)
  storageKeys: {
    authToken: 'Authtoken',
    sessionId: 'sessionId',
    sessionAuthToken: 'sessionAuthToken',
    userData: 'localUserData',
    lastApiCallTime: 'lastApiCallTime',
    lastActivity: 'userLastActivity',
    deviceId: 'deviceId',
  },

  // Cookie Configuration
  cookieConfig: {
    name: 'Authtoken',
    secure: true,
    sameSite: 'strict',
    path: '/',
  },

  // Geolocation Configuration
  geolocation: {
    apiUrl: 'https://ip-api.com/json',
    timeout: 5000,
  },

  // Callbacks
  callbacks: {
    onSessionCreated: (session) => console.log('Session created:', session),
    onSessionExpired: () => console.log('Session expired'),
    onSessionExtended: () => console.log('Session extended'),
    onForceLogout: () => console.log('Force logout'),
    onConflictDetected: (sessions) => console.log('Conflict:', sessions),
    onLogout: () => console.log('Logged out'),
    onUnauthorized: () => console.log('Unauthorized'),
  },

  // HTTP Interceptor Configuration
  useLegacyAuthHeader: false,           // Don't send legacy Authtoken header (default: false)
  interceptorSkipUrls: ['/public'],     // Additional URLs to skip
  customHeaders: {                       // Custom headers for all requests
    'X-App-Version': '1.0.0',
  },

  // Debug Mode
  debug: false,
})

Services

FgsSessionService

The main service for session management.

import { Component, inject, OnInit } from '@angular/core';
import { FgsSessionService } from '@sauravart/fgs-session-management';

@Component({...})
export class MyComponent implements OnInit {
  private sessionService = inject(FgsSessionService);

  ngOnInit() {
    // Subscribe to session events
    this.sessionService.sessionCreated$.subscribe((session) => {
      console.log('Session created:', session);
    });

    this.sessionService.sessionExpired$.subscribe(() => {
      console.log('Session expired!');
    });

    this.sessionService.sessionLocked$.subscribe(() => {
      console.log('Session locked!');
    });

    this.sessionService.sessionUnlocked$.subscribe(() => {
      console.log('Session unlocked!');
    });

    this.sessionService.networkStatusChanged$.subscribe((isOnline) => {
      console.log('Network status:', isOnline ? 'Online' : 'Offline');
    });

    this.sessionService.conflictDetected$.subscribe((sessions) => {
      console.log('Conflict detected:', sessions);
    });
  }

  // Initialize session after login
  async initializeSession(userData: any, authToken: string) {
    await this.sessionService.initializeSession(userData, authToken);
  }

  // Extend session
  extendSession() {
    this.sessionService.extendSession().subscribe();
  }

  // Logout
  logout() {
    this.sessionService.logout().subscribe();
  }

  // Lock session
  lockSession() {
    this.sessionService.lockSession();
  }

  // Unlock session
  unlockSession() {
    this.sessionService.unlockSession();
  }

  // Check if session is locked
  get isLocked() {
    return this.sessionService.getIsLocked();
  }

  // Check authentication state (computed signal)
  get isAuthenticated() {
    return this.sessionService.isAuthenticated();
  }

  // Get current session ID (computed signal)
  get sessionId() {
    return this.sessionService.currentSessionId();
  }

  // Get current user ID (computed signal)
  get userId() {
    return this.sessionService.currentUserId();
  }

  // Get full session state
  getSessionState() {
    return this.sessionService.getSessionState();
  }

  // Check if session is valid
  isSessionValid() {
    return this.sessionService.isSessionValid();
  }
}

FgsSessionTimerService

Manage session timer directly.

import { Component, inject, OnInit } from '@angular/core';
import { FgsSessionTimerService } from '@sauravart/fgs-session-management';

@Component({...})
export class MyComponent implements OnInit {
  private timerService = inject(FgsSessionTimerService);

  ngOnInit() {
    // Subscribe to timer trigger (seconds remaining in warning window)
    this.timerService.timerTrigger$.subscribe((seconds) => {
      if (seconds > 0) {
        console.log(`Warning: ${seconds} seconds remaining`);
      }
    });

    // Subscribe to session expiry
    this.timerService.sessionExpired$.subscribe(() => {
      console.log('Session expired!');
    });

    // Subscribe to warning started
    this.timerService.warningStarted$.subscribe((seconds) => {
      console.log(`Warning started with ${seconds} seconds`);
    });

    // Subscribe to timer state changes
    this.timerService.timerState$.subscribe((state) => {
      console.log('Timer state:', state);
    });
  }

  // Get remaining time in seconds
  get remainingSeconds() {
    return this.timerService.getRemainingTimeSeconds();
  }

  // Get remaining time in milliseconds
  get remainingMs() {
    return this.timerService.getRemainingTimeMs();
  }

  // Check if in warning window
  get isInWarningWindow() {
    return this.timerService.isInWarningWindow();
  }

  // Check if session expired
  get isExpired() {
    return this.timerService.isExpired();
  }

  // Manually reset timer
  resetTimer() {
    this.timerService.resetTimer();
  }

  // Pause timer (e.g., when showing modal)
  pauseTimer() {
    this.timerService.pause();
  }

  // Resume timer
  resumeTimer() {
    this.timerService.resume();
  }
}

FgsBroadcastService

Cross-tab communication service using BroadcastChannel API.

import { Component, inject, OnInit } from '@angular/core';
import { FgsBroadcastService } from '@sauravart/fgs-session-management';

@Component({...})
export class MyComponent implements OnInit {
  private broadcastService = inject(FgsBroadcastService);

  ngOnInit() {
    // Initialize the service (automatically done by FgsSessionService)
    this.broadcastService.initialize();

    // Listen for logout from other tabs
    this.broadcastService.logoutReceived$.subscribe(() => {
      console.log('Logout received from another tab');
    });

    // Listen for session expired from other tabs
    this.broadcastService.sessionExpiredReceived$.subscribe(() => {
      console.log('Session expired in another tab');
    });

    // Listen for session extended from other tabs
    this.broadcastService.sessionExtendedReceived$.subscribe(() => {
      console.log('Session extended in another tab');
    });

    // Listen for session locked from other tabs
    this.broadcastService.sessionLockedReceived$.subscribe(() => {
      console.log('Session locked in another tab');
    });

    // Listen for session unlocked from other tabs
    this.broadcastService.sessionUnlockedReceived$.subscribe(() => {
      console.log('Session unlocked in another tab');
    });

    // Listen for all messages
    this.broadcastService.messageReceived$.subscribe((message) => {
      console.log('Broadcast message:', message);
    });
  }

  // Get current tab ID
  get tabId() {
    return this.broadcastService.getTabId();
  }

  // Broadcast custom message
  broadcastMessage() {
    this.broadcastService.broadcast('SESSION_EXTENDED', { custom: 'data' });
  }

  // Distributed locking (prevent race conditions across tabs)
  async doSomethingWithLock() {
    const lockAcquired = this.broadcastService.acquireLock('my-operation');
    if (lockAcquired) {
      try {
        // Do something that should only run in one tab
        await this.performOperation();
      } finally {
        this.broadcastService.releaseLock('my-operation');
      }
    } else {
      console.log('Another tab is performing this operation');
    }
  }

  // Or use the helper method
  async doSomethingWithLockHelper() {
    const result = await this.broadcastService.withLock('my-operation', async () => {
      return await this.performOperation();
    });

    if (result === null) {
      console.log('Could not acquire lock');
    }
  }
}

FgsNetworkStatusService

Monitor network connectivity.

import { Component, inject, OnInit } from '@angular/core';
import { FgsNetworkStatusService } from '@sauravart/fgs-session-management';

@Component({...})
export class MyComponent implements OnInit {
  private networkService = inject(FgsNetworkStatusService);

  ngOnInit() {
    // Initialize the service (automatically done by FgsSessionService)
    this.networkService.initialize();

    // Subscribe to going online (includes offline duration)
    this.networkService.wentOnline$.subscribe((offlineDurationMs) => {
      console.log(`Back online after ${offlineDurationMs}ms`);
    });

    // Subscribe to going offline
    this.networkService.wentOffline$.subscribe(() => {
      console.log('Network disconnected');
    });

    // Subscribe to full status changes
    this.networkService.networkStatus$.subscribe((status) => {
      console.log('Network status:', status);
    });
  }

  // Check current online status
  get isOnline() {
    return this.networkService.isOnline;
  }

  // Get current offline duration (0 if online)
  get offlineDuration() {
    return this.networkService.currentOfflineDurationMs;
  }

  // Get full network status
  getStatus() {
    return this.networkService.getStatus();
  }

  // Manually check connectivity (makes a test request)
  async checkConnectivity() {
    const isConnected = await this.networkService.checkConnectivity();
    console.log('Connectivity check:', isConnected);
  }
}

FgsStorageService

Manage session storage (cookies, sessionStorage, localStorage).

import { Component, inject } from '@angular/core';
import { FgsStorageService } from '@sauravart/fgs-session-management';

@Component({...})
export class MyComponent {
  private storageService = inject(FgsStorageService);

  // Get stored user data
  getUserData() {
    return this.storageService.getUserData();
  }

  // Get auth token
  getAuthToken() {
    return this.storageService.getAuthToken();
  }

  // Get session ID
  getSessionId() {
    return this.storageService.getSessionId();
  }

  // Check if authenticated
  isAuthenticated() {
    return this.storageService.isAuthenticated();
  }

  // Clear all session data
  clearAll() {
    this.storageService.clearAll();
  }
}

FgsDeviceInfoService

Get device information and fingerprinting.

import { Component, inject } from '@angular/core';
import { FgsDeviceInfoService } from '@sauravart/fgs-session-management';

@Component({...})
export class MyComponent {
  private deviceService = inject(FgsDeviceInfoService);

  async getDeviceInfo() {
    // Get full device info (cached)
    const deviceInfo = await this.deviceService.getDeviceInfo();
    console.log('Device:', deviceInfo);
    // { deviceId, deviceName, browser, browserVersion, os, osVersion, ... }

    // Get geolocation (cached)
    const geolocation = await this.deviceService.getGeolocation();
    console.log('Location:', geolocation);
    // { ipAddress, location, country, city, ... }

    // Get combined session device info
    const sessionInfo = await this.deviceService.getSessionDeviceInfo();
    console.log('Session device info:', sessionInfo);
  }

  // Check device type
  get isMobile() {
    return this.deviceService.isMobile();
  }

  get isTablet() {
    return this.deviceService.isTablet();
  }

  get isDesktop() {
    return this.deviceService.isDesktop();
  }

  // Clear cache (force refresh)
  clearCache() {
    this.deviceService.clearCache();
  }
}

UI Components

Session Timeout Dialog

Automatically shows when session is about to expire with a beautiful countdown timer.

<fgs-session-timeout-dialog></fgs-session-timeout-dialog>

Features:

  • Circular SVG countdown timer
  • Color-coded countdown (blue > orange > red)
  • Extend Session button
  • Logout button
  • Dark mode support
  • Fully accessible (ARIA labels)

Session Conflict Modal

Shows when multiple active sessions are detected.

<fgs-session-conflict-modal></fgs-session-conflict-modal>

Features:

  • List of active sessions with device info
  • Device type icons (desktop/mobile)
  • Location and IP address display
  • Countdown before force logout is enabled
  • Three actions: Wait, Force Logout Others, Cancel & Logout
  • Dark mode support

Session Lock Screen

Shows when session is locked for security.

Basic usage (click to unlock):

<fgs-session-lock-screen></fgs-session-lock-screen>

With password validation:

<fgs-session-lock-screen
  [requirePassword]="true"
  [validatePassword]="validatePassword"
  (unlockRequested)="onUnlockRequested($event)"
  (logoutRequested)="onLogoutRequested()"
></fgs-session-lock-screen>
@Component({...})
export class AppComponent {
  // Custom password validation function
  validatePassword = async (password: string): Promise<boolean> => {
    try {
      const response = await this.authService.validatePassword(password);
      return response.valid;
    } catch {
      return false;
    }
  };

  onUnlockRequested(event: { password?: string }) {
    console.log('Unlock requested');
    // If validatePassword returns true, session unlocks automatically
  }

  onLogoutRequested() {
    console.log('Logout requested from lock screen');
  }
}

Features:

  • Beautiful dark gradient background
  • Animated lock icon
  • User name display (auto-detected)
  • Optional password input with visibility toggle
  • "Locked duration" display
  • Sign out option
  • Cross-tab synchronization
  • Dark mode by default

Lock/Unlock programmatically:

// Lock the session
this.sessionService.lockSession();

// Unlock the session
this.sessionService.unlockSession();

HTTP Interceptor

The interceptor automatically:

  • Adds Authorization: Bearer <token> header
  • Adds session headers (X-Session-Id, X-Session-Token, X-Last-Activity)
  • Records API calls for activity tracking
  • Handles 401/403 responses with automatic logout
  • Skips authentication for login/signup endpoints

With interceptor (recommended):

provideFgsSessionWithInterceptor(config)

Without interceptor (add manually):

import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideFgsSession, getFgsSessionInterceptor } from '@sauravart/fgs-session-management';

export const appConfig: ApplicationConfig = {
  providers: [
    provideFgsSession(config),
    provideHttpClient(
      withInterceptors([
        getFgsSessionInterceptor(),
        // ... other interceptors
      ])
    ),
  ],
};

Default skip URLs:

  • /login, /signin, /signup, /register
  • /forgot-password, /reset-password
  • /verify, /oauth
  • /Session/create

Add custom skip URLs:

provideFgsSession({
  // ...
  interceptorSkipUrls: ['/public', '/health'],
})

Route Guards

Available Guards

| Guard | Description | |-------|-------------| | fgsSessionGuard | Requires authenticated session | | fgsSessionGuardChild | For child routes | | fgsSessionGuardMatch | For lazy-loaded routes (canMatch) | | fgsGuestGuard | Only for non-authenticated users | | fgsRoleGuard(roles) | Role-based access control | | fgsPermissionGuard(permissions, requireAll?) | Permission-based access |

Usage Examples

import { Routes } from '@angular/router';
import {
  fgsSessionGuard,
  fgsSessionGuardChild,
  fgsSessionGuardMatch,
  fgsGuestGuard,
  fgsRoleGuard,
  fgsPermissionGuard,
} from '@sauravart/fgs-session-management';

export const routes: Routes = [
  // Guest only (redirect to dashboard if logged in)
  {
    path: 'login',
    component: LoginComponent,
    canActivate: [fgsGuestGuard],
  },

  // Basic authentication guard
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [fgsSessionGuard],
  },

  // Role-based (user must have ANY of these roles)
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [fgsRoleGuard(['admin', 'manager'])],
  },

  // Permission-based (user must have ANY of these permissions)
  {
    path: 'reports',
    component: ReportsComponent,
    canActivate: [fgsPermissionGuard(['view_reports', 'export_reports'])],
  },

  // Permission-based (user must have ALL permissions)
  {
    path: 'settings',
    component: SettingsComponent,
    canActivate: [fgsPermissionGuard(['read_settings', 'write_settings'], true)],
  },

  // Lazy-loaded module with canMatch
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes'),
    canMatch: [fgsSessionGuardMatch],
  },

  // Child routes protection
  {
    path: 'account',
    component: AccountLayoutComponent,
    canActivate: [fgsSessionGuard],
    canActivateChild: [fgsSessionGuardChild],
    children: [
      { path: 'profile', component: ProfileComponent },
      { path: 'settings', component: SettingsComponent },
    ],
  },
];

Backend API Implementation Guide

Your backend needs to implement the following endpoints to work with this library. All endpoints should accept and return JSON.

Required Endpoints Overview

| Endpoint | Method | Description | |----------|--------|-------------| | /session/create | POST | Create a new session after user login | | /session/validate | POST | Validate if a session is still active | | /session/refresh | POST | Extend/refresh an existing session | | /session/revoke | POST | Terminate a specific session | | /session/list | GET | List all active sessions for a user | | /auth/logout | POST | Logout and cleanup session |


1. Create Session

Creates a new session when a user logs in. Called automatically after initializeSession().

Endpoint: POST /session/create

Request Headers:

Content-Type: application/json
Authorization: Bearer <auth_token>

Request Body:

{
  "userId": "user-123",
  "userCode": "USR001",
  "deviceId": "d4f5e6a7-b8c9-4d3e-a2b1-c0d9e8f7a6b5",
  "deviceName": "Chrome on Windows",
  "browser": "Chrome",
  "browserVersion": "120.0.0",
  "os": "Windows",
  "osVersion": "10",
  "ipAddress": "103.25.142.85",
  "location": "Mumbai, IN",
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
  "screenResolution": "1920x1080",
  "timezone": "Asia/Kolkata",
  "language": "en-IN"
}

Success Response (200 OK):

{
  "success": true,
  "sessionId": "sess_abc123def456",
  "sessionAuthToken": "sat_xyz789...",
  "authToken": "eyJhbGciOiJIUzI1NiIs...",
  "expiresAt": "2024-01-15T12:30:00Z",
  "message": "Session created successfully"
}

Error Responses:

| Status | Code | Description | |--------|------|-------------| | 400 | INVALID_REQUEST | Missing required fields | | 401 | UNAUTHORIZED | Invalid or expired auth token | | 409 | SESSION_CONFLICT | Another active session exists (if single-session policy) | | 500 | SERVER_ERROR | Internal server error |

Error Response Format:

{
  "success": false,
  "error": "SESSION_CONFLICT",
  "message": "Another active session already exists",
  "activeSessions": [
    {
      "sessionId": "sess_existing123",
      "deviceName": "Firefox on MacOS",
      "ipAddress": "49.36.178.92",
      "location": "Bangalore, IN",
      "lastActivity": "2024-01-15T15:55:00Z"
    }
  ]
}

Implementation Notes:

  • Generate a unique sessionId (UUID recommended)
  • Store session with: userId, deviceId, deviceName, ipAddress, createdAt, expiresAt, lastActivity
  • Optionally return a new authToken with sessionId embedded in JWT claims
  • Consider implementing max sessions per user policy

2. Validate Session

Validates if the current session is still active. Called periodically (every 60 seconds by default) and when the tab regains focus.

Endpoint: POST /session/validate

Request Headers:

Content-Type: application/json
Authorization: Bearer <auth_token>
X-Session-Id: sess_abc123def456
X-Session-Token: sat_xyz789...

Request Body:

{
  "sessionId": "sess_abc123def456"
}

Success Response (200 OK):

{
  "valid": true,
  "sessionId": "sess_abc123def456",
  "expiresAt": "2024-01-15T12:30:00Z",
  "message": "Session is valid"
}

Invalid Session Response (200 OK):

{
  "valid": false,
  "message": "Session has expired or was revoked"
}

Error Responses:

| Status | Code | Description | |--------|------|-------------| | 401 | UNAUTHORIZED | Invalid auth token | | 404 | SESSION_NOT_FOUND | Session doesn't exist |

Implementation Notes:

  • Check if session exists and hasn't expired
  • Check if session wasn't revoked/terminated
  • Update lastActivity timestamp on successful validation
  • Return valid: false instead of 401 for expired sessions (allows graceful handling)

3. Refresh Session

Extends the session expiry time. Called when user clicks "Extend Session" or on user activity (throttled).

Endpoint: POST /session/refresh

Request Headers:

Content-Type: application/json
Authorization: Bearer <auth_token>
X-Session-Id: sess_abc123def456
X-Session-Token: sat_xyz789...
X-Last-Activity: 2024-01-15T10:20:00Z

Request Body:

{
  "sessionId": "sess_abc123def456"
}

Success Response (200 OK):

{
  "success": true,
  "sessionId": "sess_abc123def456",
  "expiresAt": "2024-01-15T12:45:00Z",
  "message": "Session extended successfully"
}

Error Responses:

| Status | Code | Description | |--------|------|-------------| | 401 | UNAUTHORIZED | Invalid auth token | | 404 | SESSION_NOT_FOUND | Session doesn't exist | | 410 | SESSION_EXPIRED | Session has already expired |

Implementation Notes:

  • Extend expiresAt by the configured session timeout duration
  • Update lastActivity timestamp
  • Reject if session is already expired or revoked

4. Revoke Session

Terminates a specific session. Used when user wants to logout other sessions or force logout from conflict modal.

Endpoint: POST /session/revoke

Request Headers:

Content-Type: application/json
Authorization: Bearer <auth_token>
X-Session-Id: sess_abc123def456

Request Body:

{
  "sessionId": "sess_other789",
  "reason": "user_requested"
}

Revoke All Other Sessions:

{
  "revokeAll": true,
  "exceptSessionId": "sess_abc123def456"
}

Success Response (200 OK):

{
  "success": true,
  "message": "Session revoked successfully",
  "revokedCount": 1
}

Error Responses:

| Status | Code | Description | |--------|------|-------------| | 401 | UNAUTHORIZED | Invalid auth token | | 403 | FORBIDDEN | Cannot revoke another user's session | | 404 | SESSION_NOT_FOUND | Session doesn't exist |

Implementation Notes:

  • Mark session as revoked/terminated in database
  • Only allow users to revoke their own sessions
  • Support revoking all sessions except current one
  • Consider sending push notification to revoked session

5. List Sessions

Returns all active sessions for the current user. Used for multi-session conflict detection.

Endpoint: GET /session/list

Request Headers:

Authorization: Bearer <auth_token>
X-Session-Id: sess_abc123def456

Query Parameters (optional):

?userId=user-123&includeExpired=false

Success Response (200 OK):

{
  "success": true,
  "sessions": [
    {
      "sessionId": "sess_abc123def456",
      "deviceName": "Chrome on Windows",
      "browser": "Chrome",
      "browserVersion": "120.0.0",
      "os": "Windows",
      "osVersion": "10",
      "ipAddress": "103.25.142.85",
      "location": "Mumbai, IN",
      "lastActivity": "2024-01-15T15:55:00Z",
      "createdAt": "2024-01-15T13:30:00Z",
      "expiresAt": "2024-01-15T18:00:00Z",
      "isCurrent": true
    },
    {
      "sessionId": "sess_xyz789012",
      "deviceName": "Safari on iPhone",
      "browser": "Safari",
      "browserVersion": "17.0",
      "os": "iOS",
      "osVersion": "17.2",
      "ipAddress": "49.36.178.92",
      "location": "Bangalore, IN",
      "lastActivity": "2024-01-15T14:45:00Z",
      "createdAt": "2024-01-15T13:00:00Z",
      "expiresAt": "2024-01-15T17:00:00Z",
      "isCurrent": false
    }
  ],
  "totalCount": 2
}

Error Responses:

| Status | Code | Description | |--------|------|-------------| | 401 | UNAUTHORIZED | Invalid auth token |

Implementation Notes:

  • Return only active (non-expired, non-revoked) sessions by default
  • Mark the current session with isCurrent: true
  • Sort by lastActivity descending (most recent first)
  • Include device/location info for user to identify sessions

6. Logout

Logs out the user and terminates the current session.

Endpoint: POST /auth/logout

Request Headers:

Content-Type: application/json
Authorization: Bearer <auth_token>
X-Session-Id: sess_abc123def456

Request Body (optional):

{
  "sessionId": "sess_abc123def456",
  "logoutAllSessions": false
}

Success Response (200 OK):

{
  "success": true,
  "message": "Logged out successfully"
}

Error Responses:

| Status | Code | Description | |--------|------|-------------| | 401 | UNAUTHORIZED | Invalid auth token (still perform cleanup) |

Implementation Notes:

  • Revoke the current session
  • Optionally revoke all sessions if logoutAllSessions: true
  • Invalidate the auth token if using token blacklist
  • Always return 200 even if session already expired (idempotent)

Common HTTP Headers

Request Headers Sent by Library

| Header | Description | Example | |--------|-------------|---------| | Authorization | Bearer token for authentication | Bearer eyJhbGciOi... | | X-Session-Id | Current session identifier | sess_abc123def456 | | X-Session-Token | Session-specific auth token | sat_xyz789... | | X-Last-Activity | Timestamp of last user activity | 2024-01-15T10:20:00Z | | Content-Type | Request body format | application/json |

Response Headers (Recommended)

| Header | Description | Example | |--------|-------------|---------| | X-Session-Expires | When the session will expire | 2024-01-15T12:30:00Z | | X-Session-Remaining | Seconds until expiry | 3600 |


Error Response Format

All error responses should follow this format for consistent handling:

{
  "success": false,
  "error": "ERROR_CODE",
  "message": "Human-readable error message",
  "details": {
    "field": "Additional context if needed"
  }
}

Standard Error Codes

| Code | HTTP Status | Description | |------|-------------|-------------| | UNAUTHORIZED | 401 | Invalid or missing auth token | | FORBIDDEN | 403 | Valid token but insufficient permissions | | SESSION_NOT_FOUND | 404 | Session ID doesn't exist | | SESSION_EXPIRED | 410 | Session has expired | | SESSION_CONFLICT | 409 | Another active session exists | | INVALID_REQUEST | 400 | Missing or invalid request parameters | | RATE_LIMITED | 429 | Too many requests | | SERVER_ERROR | 500 | Internal server error |


Database Schema (Recommended)

CREATE TABLE sessions (
  id VARCHAR(50) PRIMARY KEY,           -- sessionId (e.g., sess_abc123)
  user_id VARCHAR(50) NOT NULL,         -- Reference to users table
  user_code VARCHAR(50),                -- Optional user code
  device_id VARCHAR(100) NOT NULL,      -- Unique device fingerprint
  device_name VARCHAR(255),             -- Human-readable device name
  browser VARCHAR(50),
  browser_version VARCHAR(20),
  os VARCHAR(50),
  os_version VARCHAR(20),
  ip_address VARCHAR(45),               -- Supports IPv6
  location VARCHAR(255),
  user_agent TEXT,
  screen_resolution VARCHAR(20),
  timezone VARCHAR(50),
  language VARCHAR(10),
  session_auth_token VARCHAR(255),      -- Optional session-specific token
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  expires_at TIMESTAMP NOT NULL,
  last_activity TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  revoked_at TIMESTAMP,                 -- NULL if active
  revoke_reason VARCHAR(50),            -- 'user_requested', 'expired', 'forced', etc.
  is_active BOOLEAN GENERATED ALWAYS AS (revoked_at IS NULL AND expires_at > CURRENT_TIMESTAMP),

  INDEX idx_user_active (user_id, is_active),
  INDEX idx_expires (expires_at),
  INDEX idx_device (device_id)
);

API Response Formats

Create Session Request

interface CreateSessionRequest {
  userId: string;
  userCode?: string;
  deviceId: string;
  deviceName: string;
  browser: string;
  browserVersion?: string;
  os: string;
  osVersion?: string;
  ipAddress: string;
  location?: string;
  userAgent: string;
  screenResolution?: string;
  timezone?: string;
  language?: string;
}

Create Session Response

interface CreateSessionResponse {
  sessionId: string;
  sessionAuthToken?: string;
  authToken?: string;      // New token with sessionId embedded
  expiresAt?: string;
  message?: string;
  success?: boolean;
}

Validate Session Response

interface ValidateSessionResponse {
  valid: boolean;
  sessionId?: string;
  expiresAt?: string;
  message?: string;
}

Active Sessions Response

interface ActiveSessionResponse {
  sessionId: string;
  deviceName?: string;
  browser?: string;
  os?: string;
  ipAddress?: string;
  location?: string;
  lastActivity?: string;
  createdAt?: string;
  isCurrent?: boolean;
}

Tailwind CSS Setup

The UI components use Tailwind CSS classes. If you're using Tailwind, add the library to your content configuration:

// tailwind.config.js
module.exports = {
  content: [
    "./src/**/*.{html,ts}",
    "./node_modules/@sauravart/fgs-session-management/**/*.{html,ts,mjs}"
  ],
  darkMode: 'class', // or 'media'
  // ... rest of config
}

Without Tailwind: The components include all necessary styles and will work without Tailwind installed, though custom Tailwind themes won't apply.

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

BroadcastChannel API Fallback: For browsers that don't support BroadcastChannel, the library automatically falls back to localStorage events for cross-tab communication.

Changelog

v1.1.0

  • Added cross-tab synchronization using BroadcastChannel API
  • Added FgsBroadcastService for cross-tab communication
  • Added FgsNetworkStatusService for online/offline detection
  • Added session lock/unlock feature with FgsSessionLockScreenComponent
  • Added proactive session refresh before expiry
  • Added error recovery with retry for session creation (3 attempts with exponential backoff)
  • Added distributed locking for conflict detection to prevent race conditions
  • Added periodic session validation (every 60 seconds)
  • Added network status handling (validates session when coming back online)
  • Fixed race condition in multi-tab conflict detection
  • Changed useLegacyAuthHeader default to false
  • Added new UI configuration options: showLockScreen, lockScreenTitle, lockScreenMessage
  • Added @angular/forms as peer dependency

v1.0.0

  • Initial release
  • Session timeout management with configurable timeout
  • Activity tracking (mouse, keyboard, scroll, touch, visibility)
  • Multi-session conflict detection
  • UI components (timeout dialog, conflict modal)
  • Route guards (session, guest, role, permission)
  • HTTP interceptor with automatic token handling
  • Device fingerprinting
  • IP geolocation support

License

MIT License - see LICENSE for details.

Author

Figment Global Solutions

Support

For issues and feature requests, please visit: https://github.com/FigmentGlobalSolution/session_management/issues