Now.js Framework Documentation

Now.js Framework Documentation

Authentication System

EN 31 Oct 2025 01:19

Authentication System

Overview documentation for the Now.js Framework Authentication System

📋 Table of Contents

  1. Overview
  2. System Architecture
  3. Core Components
  4. Quick Start
  5. Authentication Flows
  6. Usage Examples
  7. Best Practices
  8. Security Considerations
  9. Related Documentation

Overview

The Now.js Authentication System is a comprehensive and secure system designed to manage authentication and authorization in modern web applications.

Key Features

  • JWT Authentication: Supports JWT tokens (Access & Refresh tokens)
  • Multiple Auth Strategies: Bearer, Basic, OAuth, Hybrid
  • HttpOnly Cookie: Securely stores tokens in httpOnly cookies
  • Auto Token Refresh: Automatically refreshes tokens before expiry
  • Route Guards: Protects routes based on permissions and roles
  • CSRF Protection: Prevents CSRF attacks
  • Error Handling: Automatic error handling with retry logic
  • Loading States: Displays loading states for various operations
  • Session Management: Manages session and user state
  • Social Login: Supports OAuth social providers

When to Use

Use Authentication System when:

  • Application requires user authentication
  • Need role-based access control (RBAC) system
  • Need to protect routes based on permissions
  • Need token-based authentication
  • Need social login integration

Don't use when:

  • Application is public and doesn't require authentication
  • Need simplicity (may use basic auth instead)

System Architecture

The Authentication System consists of 5 core components:

┌─────────────────────────────────────────────────────────────┐
│                     Application Layer                       │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │   Router     │  │     Views    │  │   Components │     │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘     │
└─────────┼──────────────────┼──────────────────┼─────────────┘
          │                  │                  │
          ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────────┐
│                   Authentication Layer                       │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │  AuthGuard   │  │ AuthManager  │  │ Error Handler│     │
│  │ (Route Guard)│  │(Core Manager)│  │(Error Handle)│     │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘     │
│         │                  │                  │              │
│         │    ┌─────────────┼─────────────┐   │              │
│         │    │             │             │   │              │
│         ▼    ▼             ▼             ▼   ▼              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │TokenService  │  │LoadingManager│  │ SecurityMgr  │     │
│  │(Token Mgmt)  │  │(Loading UI)  │  │(CSRF, etc.)  │     │
│  └──────────────┘  └──────────────┘  └──────────────┘     │
└─────────────────────────────────────────────────────────────┘
          │                  │                  │
          ▼                  ▼                  ▼
┌─────────────────────────────────────────────────────────────┐
│                      Storage Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │   Cookies    │  │ LocalStorage │  │SessionStorage│     │
│  │(HttpOnly JWT)│  │(User Data)   │  │(Temp Data)   │     │
│  └──────────────┘  └──────────────┘  └──────────────┘     │
└─────────────────────────────────────────────────────────────┘

Data Flow

  1. User Login:

    User → AuthManager.login() → API → Response (JWT)
        → TokenService.store() → HttpOnly Cookie
        → AuthManager.setAuthenticatedUser() → Update State
  2. Protected Route Access:

    Router → AuthGuard.checkRoute() → AuthManager.checkAuthStatus()
         → TokenService.getToken() → Validate Token
         → Check Permissions/Roles → Allow/Deny
  3. Token Refresh:

    Request → 401 Error → AuthManager.refreshToken()
          → TokenService.getRefreshToken() → API
          → New Access Token → Continue Request

Core Components

1. AuthManager (Core)

File: Now/js/AuthManager.js
Role: Manages entire authentication lifecycle

Key Features:

  • Login/Logout flows
  • Token management (access & refresh)
  • Session state management
  • Auto token refresh
  • Social login integration
  • CSRF protection

Documentation: AuthManager.md

2. TokenService

File: Now/js/TokenService.js
Role: Manages JWT tokens (parsing, validation, storage)

Key Features:

  • JWT token parsing
  • Token validation & expiry check
  • Storage management (cookie/localStorage)
  • User data extraction

Documentation: TokenService.md

3. AuthGuard

File: Now/js/AuthGuard.js
Role: Protects routes and checks permissions

Key Features:

  • Route protection
  • Role-based access control
  • Permission checking
  • Custom validation
  • Intended route storage

Documentation: AuthGuard.md

4. AuthErrorHandler

File: Now/js/AuthErrorHandler.js
Role: Handles authentication errors

Key Features:

  • 11+ error types handling
  • Automatic error actions (redirect, render, retry)
  • Token refresh on expiry
  • Rate limiting
  • Custom error handling

Documentation: AuthErrorHandler.md

5. AuthLoadingManager

File: Now/js/AuthLoadingManager.js
Role: Manages loading states for auth operations

Key Features:

  • 9+ operation types
  • Loading overlays
  • Progress tracking
  • Timeout handling
  • Custom loading UI

Documentation: AuthLoadingManager.md

Quick Start

1. Installation

Authentication system loads with Now.js Framework:

<!-- AuthManager and dependencies -->
<script src="/Now/js/TokenService.js"></script>
<script src="/Now/js/AuthLoadingManager.js"></script>
<script src="/Now/js/AuthErrorHandler.js"></script>
<script src="/Now/js/AuthGuard.js"></script>
<script src="/Now/js/AuthManager.js"></script>

2. Basic Setup

// Initialize AuthManager
await AuthManager.init({
  enabled: true,
  type: 'jwt-httponly',

  endpoints: {
    login: '/api/v1/auth/login',
    logout: '/api/v1/auth/logout',
    verify: '/api/v1/auth/verify',
    refresh: '/api/v1/auth/refresh'
  },

  security: {
    csrf: true,
    autoRefresh: true
  },

  redirects: {
    afterLogin: '/dashboard',
    afterLogout: '/login',
    unauthorized: '/login'
  }
});

console.log('Authentication initialized!');

3. User Login

// Simple login
const result = await AuthManager.login({
  username: 'user@example.com',
  password: 'secret123'
});

if (result.success) {
  console.log('Login successful!');
  console.log('User:', AuthManager.getUser());
  // Will redirect to /dashboard automatically
}

4. Check Authentication Status

// Check if user is authenticated
if (AuthManager.isAuthenticated()) {
  const user = AuthManager.getUser();
  console.log('Welcome,', user.name);
} else {
  console.log('Please login');
}

5. Logout

// Logout user
await AuthManager.logout();
console.log('Logged out successfully');
// Will redirect to /login automatically

Authentication Flows

1. Login Flow (Complete)

// Step 1: User submits login form
document.getElementById('loginForm').addEventListener('submit', async (e) => {
  e.preventDefault();

  // Step 2: Call AuthManager.login()
  const result = await AuthManager.login({
    username: document.getElementById('username').value,
    password: document.getElementById('password').value
  });

  // Step 3: Handle result
  if (result.success) {
    // Login successful
    // - JWT stored in httpOnly cookie
    // - User data stored in localStorage
    // - Redirected to dashboard
    console.log('Login successful!');
  } else {
    // Login failed
    console.error('Login failed:', result.error);
    alert(result.error);
  }
});

Behind the scenes:

  1. AuthLoadingManager shows loading overlay
  2. AuthManager calls login endpoint
  3. Server validates credentials
  4. Server sends JWT tokens back
  5. TokenService stores access token in httpOnly cookie
  6. TokenService stores refresh token in httpOnly cookie (if available)
  7. AuthManager stores user data in localStorage
  8. AuthManager updates state (authenticated = true)
  9. AuthManager redirects to afterLogin route
  10. AuthLoadingManager hides loading overlay

2. Protected Route Flow

// Router configuration with auth guard
await Router.init({
  routes: [
    {
      path: '/dashboard',
      handler: 'renderDashboard',
      metadata: {
        requiresAuth: true,
        roles: ['user', 'admin'],
        permissions: ['read:dashboard']
      }
    }
  ],

  auth: {
    enabled: true,
    guard: AuthGuard.checkRoute,
    defaultRequireAuth: false,
    redirects: {
      unauthorized: '/login',
      forbidden: '/403'
    }
  }
});

// When user navigates to /dashboard
Router.navigate('/dashboard');

Behind the scenes:

  1. Router calls AuthGuard.checkRoute()
  2. AuthGuard calls AuthManager.checkAuthStatus()
  3. AuthManager checks authentication status
  4. If token exists but not verified → call verify endpoint
  5. AuthGuard checks roles and permissions
  6. If passed → allow navigation
  7. If not passed → redirect to unauthorized route

3. Token Refresh Flow

// Automatic token refresh (configured in AuthManager)
await AuthManager.init({
  security: {
    autoRefresh: true,
    refreshBeforeExpiry: 5 * 60 * 1000 // 5 minutes
  }
});

// Manual token refresh
const refreshed = await AuthManager.refreshToken();
if (refreshed) {
  console.log('Token refreshed successfully');
}

Behind the scenes:

  1. AuthManager sets timer 5 minutes before token expires
  2. Timer triggers → call refreshToken()
  3. TokenService reads refresh token from cookie
  4. AuthManager calls refresh endpoint with refresh token
  5. Server validates refresh token
  6. Server sends new access token back
  7. TokenService stores new access token
  8. AuthManager sets new timer

Auto refresh on 401:

// Configured in HttpClient interceptors
httpClient.on('response', async (response) => {
  if (response.status === 401) {
    // Try to refresh token
    const refreshed = await AuthManager.refreshToken();

    if (refreshed) {
      // Retry original request with new token
      return httpClient.retry(response.config);
    } else {
      // Refresh failed - logout user
      await AuthManager.logout(false);
      Router.navigate('/login');
    }
  }
});

4. Error Handling Flow

// AuthErrorHandler is automatically integrated
// But you can customize error handling

document.addEventListener('auth:error', (e) => {
  const { errorType, message, action } = e.detail;

  console.log('Auth error:', errorType);
  console.log('Message:', message);
  console.log('Action taken:', action);

  // Custom handling
  if (errorType === 'TOKEN_EXPIRED') {
    console.log('Token expired - refreshing...');
  }
});

Error types handled:

  • UNAUTHORIZED - No token or invalid
  • FORBIDDEN - No permission to access
  • TOKEN_EXPIRED - Token expired
  • TOKEN_INVALID - Token is invalid
  • SESSION_EXPIRED - Session expired
  • RATE_LIMITED - Too many requests
  • ACCOUNT_LOCKED - Account is locked
  • And more... (see AuthErrorHandler.md)

Usage Examples

1. Complete Login Form

<!DOCTYPE html>
<html>
<head>
  <title>Login</title>
</head>
<body>
  <form id="loginForm">
    <input type="text" id="username" placeholder="Username" required>
    <input type="password" id="password" placeholder="Password" required>
    <button type="submit">Login</button>
    <div id="error" style="color: red;"></div>
  </form>

  <script src="/Now/js/TokenService.js"></script>
  <script src="/Now/js/AuthLoadingManager.js"></script>
  <script src="/Now/js/AuthErrorHandler.js"></script>
  <script src="/Now/js/AuthManager.js"></script>

  <script>
    // Initialize AuthManager
    (async () => {
      await AuthManager.init({
        enabled: true,
        endpoints: {
          login: '/api/v1/auth/login',
          logout: '/api/v1/auth/logout'
        },
        redirects: {
          afterLogin: '/dashboard'
        }
      });

      // Handle login form
      document.getElementById('loginForm').addEventListener('submit', async (e) => {
        e.preventDefault();

        const errorDiv = document.getElementById('error');
        errorDiv.textContent = '';

        try {
          const result = await AuthManager.login({
            username: document.getElementById('username').value,
            password: document.getElementById('password').value
          });

          if (result.success) {
            // Login successful - will auto-redirect
            console.log('Login successful!');
          } else {
            // Show error
            errorDiv.textContent = result.error || 'Login failed';
          }
        } catch (error) {
          errorDiv.textContent = 'An error occurred. Please try again.';
          console.error('Login error:', error);
        }
      });
    })();
  </script>
</body>
</html>

2. Protected Dashboard

<!DOCTYPE html>
<html>
<head>
  <title>Dashboard</title>
</head>
<body>
  <div id="dashboard">
    <h1>Welcome, <span id="userName"></span>!</h1>
    <button id="logoutBtn">Logout</button>
  </div>

  <script src="/Now/js/TokenService.js"></script>
  <script src="/Now/js/AuthManager.js"></script>

  <script>
    (async () => {
      // Initialize AuthManager
      await AuthManager.init({
        enabled: true
      });

      // Check authentication
      if (!AuthManager.isAuthenticated()) {
        // Not logged in - redirect to login
        window.location.href = '/login';
        return;
      }

      // Get user data
      const user = AuthManager.getUser();
      document.getElementById('userName').textContent = user.name;

      // Handle logout
      document.getElementById('logoutBtn').addEventListener('click', async () => {
        await AuthManager.logout();
        // Will auto-redirect to /login
      });
    })();
  </script>
</body>
</html>

3. Role-Based UI

// Show/hide elements based on user role
(async () => {
  await AuthManager.init({ enabled: true });

  if (!AuthManager.isAuthenticated()) {
    window.location.href = '/login';
    return;
  }

  const user = AuthManager.getUser();

  // Check role
  if (AuthManager.hasRole('admin')) {
    // Show admin panel
    document.getElementById('adminPanel').style.display = 'block';
  }

  // Check permission
  if (AuthManager.hasPermission('edit:posts')) {
    // Show edit button
    document.getElementById('editButton').style.display = 'block';
  }
})();

4. API Calls with Auth

// ApiService automatically includes auth token
const response = await ApiService.get('/api/users');

if (response.ok) {
  console.log('Users:', response.data);
} else if (response.status === 401) {
  // Token expired - AuthManager will handle automatically
  console.log('Token expired - refreshing...');
} else {
  console.error('Error:', response.error);
}

5. Social Login

// Initialize with social login endpoints
await AuthManager.init({
  enabled: true,
  endpoints: {
    social: '/api/v1/auth/social/{provider}',
    callback: '/api/v1/auth/callback'
  }
});

// Google login
document.getElementById('googleLogin').addEventListener('click', async () => {
  await AuthManager.socialLogin('google', {
    redirect_uri: 'http://localhost/auth/callback'
  });
  // Will open popup for Google OAuth
});

// Facebook login
document.getElementById('facebookLogin').addEventListener('click', async () => {
  await AuthManager.socialLogin('facebook', {
    redirect_uri: 'http://localhost/auth/callback'
  });
});

// Handle callback
if (window.location.pathname === '/auth/callback') {
  const params = new URLSearchParams(window.location.search);
  const code = params.get('code');
  const provider = params.get('provider');

  if (code && provider) {
    const result = await AuthManager.handleAuthCallback({
      code,
      provider
    });

    if (result.success) {
      console.log('Social login successful!');
      window.location.href = '/dashboard';
    }
  }
}

6. Custom Validation

// Router with custom validation
await Router.init({
  routes: [
    {
      path: '/admin/settings',
      handler: 'renderSettings',
      metadata: {
        requiresAuth: true,
        validate: async (to, from, router) => {
          const user = AuthManager.getUser();

          // Custom validation: check subscription status
          if (!user.subscription || user.subscription.status !== 'active') {
            return {
              allowed: false,
              action: 'redirect',
              target: '/subscribe',
              reason: 'Subscription required'
            };
          }

          // Custom validation: check IP whitelist
          const response = await fetch('/api/check-ip');
          const { allowed } = await response.json();

          if (!allowed) {
            return {
              allowed: false,
              action: 'block',
              reason: 'IP not whitelisted'
            };
          }

          return { allowed: true };
        }
      }
    }
  ],

  auth: {
    enabled: true,
    guard: AuthGuard.checkRoute
  }
});

Best Practices

1. Token Security

DO:

  • Use httpOnly cookies to store tokens
  • Set secure flag for production (HTTPS)
  • Use SameSite=Strict or Lax
  • Rotate refresh tokens regularly
  • Set appropriate token expiry (access: 15min, refresh: 7d)

DON'T:

  • Store tokens in localStorage (XSS risk)
  • Store sensitive data in JWT payload
  • Send tokens in URL parameters
  • Use tokens without expiry
// ✅ Good - httpOnly cookie
await AuthManager.init({
  type: 'jwt-httponly',
  token: {
    cookieOptions: {
      httpOnly: true,  // Cannot be accessed by JavaScript
      secure: true,    // HTTPS only
      sameSite: 'Strict'
    }
  }
});

// ❌ Bad - localStorage
localStorage.setItem('token', token); // Vulnerable to XSS

2. CSRF Protection

DO:

  • Enable CSRF protection
  • Send CSRF token in headers
  • Validate CSRF token on server
  • Use SameSite cookies
// ✅ Good - CSRF enabled
await AuthManager.init({
  security: {
    csrf: true,
    csrfIncludeSafeMethods: true
  }
});

// CSRF token automatically included in requests
const response = await ApiService.post('/api/users', userData);

3. Error Handling

DO:

  • Handle all error types
  • Show user-friendly error messages
  • Log errors for debugging
  • Retry with appropriate logic
// ✅ Good - comprehensive error handling
document.addEventListener('auth:error', (e) => {
  const { errorType, message } = e.detail;

  // Log for debugging
  console.error('Auth error:', errorType, message);

  // User-friendly message
  switch (errorType) {
    case 'TOKEN_EXPIRED':
      showNotification('Your session has expired. Please login again.');
      break;
    case 'FORBIDDEN':
      showNotification('You do not have permission to access this page.');
      break;
    default:
      showNotification('An error occurred. Please try again.');
  }
});

4. Loading States

DO:

  • Show loading indicators for async operations
  • Provide clear feedback
  • Disable buttons during loading
  • Set appropriate timeouts
// ✅ Good - proper loading handling
async function handleLogin(credentials) {
  const submitBtn = document.getElementById('submitBtn');

  // Disable button during login
  submitBtn.disabled = true;
  submitBtn.textContent = 'Logging in...';

  try {
    const result = await AuthManager.login(credentials);

    if (result.success) {
      // Success feedback
      submitBtn.textContent = 'Success! Redirecting...';
    }
  } catch (error) {
    // Error feedback
    submitBtn.textContent = 'Login Failed';
  } finally {
    // Re-enable button
    setTimeout(() => {
      submitBtn.disabled = false;
      submitBtn.textContent = 'Login';
    }, 2000);
  }
}

5. Session Management

DO:

  • Check session when user returns
  • Clear session on logout
  • Handle session expiry gracefully
  • Use appropriate session timeout
// ✅ Good - session check on page load
window.addEventListener('load', async () => {
  await AuthManager.init({ enabled: true });

  if (AuthManager.isAuthenticated()) {
    // Verify session is still valid
    const valid = await AuthManager.checkAuthStatus();

    if (!valid) {
      // Session expired
      console.log('Session expired - please login');
      await AuthManager.logout(false); // Don't call server
      window.location.href = '/login';
    }
  }
});

// Handle page visibility
document.addEventListener('visibilitychange', async () => {
  if (!document.hidden && AuthManager.isAuthenticated()) {
    // User returned to page - verify session
    await AuthManager.checkAuthStatus();
  }
});

6. Route Protection

DO:

  • Use AuthGuard for protected routes
  • Set default auth requirement
  • Specify clear roles/permissions
  • Handle unauthorized access gracefully
// ✅ Good - comprehensive route protection
await Router.init({
  routes: [
    // Public routes
    { path: '/', handler: 'home', metadata: { public: true } },
    { path: '/about', handler: 'about', metadata: { public: true } },

    // Guest-only routes
    {
      path: '/login',
      handler: 'login',
      metadata: {
        guestOnly: true,
        redirectOnAuth: '/dashboard'
      }
    },

    // Protected routes with roles
    {
      path: '/dashboard',
      handler: 'dashboard',
      metadata: {
        requiresAuth: true,
        roles: ['user', 'admin']
      }
    },

    // Admin-only routes
    {
      path: '/admin/*',
      handler: 'admin',
      metadata: {
        requiresAuth: true,
        roles: ['admin'],
        permissions: ['admin:access']
      }
    }
  ],

  auth: {
    enabled: true,
    guard: AuthGuard.checkRoute,
    defaultRequireAuth: false,
    redirects: {
      unauthorized: '/login',
      forbidden: '/403'
    }
  }
});

7. Testing Authentication

DO:

  • Test all authentication flows
  • Test error scenarios
  • Test token refresh
  • Test route protection
// ✅ Good - comprehensive testing
describe('Authentication', () => {
  beforeEach(async () => {
    await AuthManager.init({ enabled: true });
    AuthManager.clearAuthData();
  });

  it('should login successfully', async () => {
    const result = await AuthManager.login({
      username: 'test@example.com',
      password: 'password123'
    });

    expect(result.success).toBe(true);
    expect(AuthManager.isAuthenticated()).toBe(true);
  });

  it('should handle invalid credentials', async () => {
    const result = await AuthManager.login({
      username: 'test@example.com',
      password: 'wrongpassword'
    });

    expect(result.success).toBe(false);
    expect(result.error).toBeTruthy();
  });

  it('should refresh token before expiry', async () => {
    // Login first
    await AuthManager.login({ username: 'test', password: 'test' });

    // Mock token near expiry
    const token = TokenService.getToken();
    const payload = TokenService.parseToken(token);
    payload.exp = Math.floor(Date.now() / 1000) + 240; // 4 minutes

    // Should trigger auto refresh
    await new Promise(resolve => setTimeout(resolve, 1000));

    expect(AuthManager.state.refreshTimer).toBeTruthy();
  });

  it('should protect routes based on roles', async () => {
    // Login as regular user
    await AuthManager.login({ username: 'user', password: 'test' });

    // Try to access admin route
    const result = await AuthGuard.checkRoute(
      { path: '/admin', metadata: { roles: ['admin'] } },
      null,
      Router
    );

    expect(result.allowed).toBe(false);
    expect(result.action).toBe('redirect');
  });
});

Security Considerations

1. Token Security

Threats:

  • XSS (Cross-Site Scripting)
  • CSRF (Cross-Site Request Forgery)
  • Token theft
  • Session hijacking

Mitigations:

// ✅ Use httpOnly cookies
await AuthManager.init({
  type: 'jwt-httponly',
  token: {
    cookieOptions: {
      httpOnly: true,     // Prevent XSS
      secure: true,       // HTTPS only
      sameSite: 'Strict'  // Prevent CSRF
    }
  },
  security: {
    csrf: true            // CSRF protection
  }
});

// ✅ Sanitize user inputs
const sanitize = (str) => {
  const div = document.createElement('div');
  div.textContent = str;
  return div.innerHTML;
};

const username = sanitize(userInput);

2. Rate Limiting

Threats:

  • Brute force attacks
  • DDoS attacks

Mitigations:

// ✅ Enable rate limiting
await AuthManager.init({
  security: {
    rateLimiting: true,
    maxLoginAttempts: 5,
    lockoutTime: 30 * 60 * 1000 // 30 minutes
  }
});

// Server-side rate limiting (example)
// Use libraries like express-rate-limit
const rateLimit = require('express-rate-limit');

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 requests per windowMs
  message: 'Too many login attempts, please try again later'
});

app.post('/api/v1/auth/login', loginLimiter, (req, res) => {
  // Login logic
});

3. Password Security

Best Practices:

  • Don't store passwords in plaintext
  • Use strong hashing algorithms (bcrypt, argon2)
  • Set password requirements
  • Use password strength meter
// ✅ Client-side validation
function validatePassword(password) {
  const minLength = 8;
  const hasUpperCase = /[A-Z]/.test(password);
  const hasLowerCase = /[a-z]/.test(password);
  const hasNumbers = /\d/.test(password);
  const hasSpecialChar = /[!@#$%^&*]/.test(password);

  if (password.length < minLength) {
    return { valid: false, message: 'Password must be at least 8 characters' };
  }

  if (!hasUpperCase || !hasLowerCase || !hasNumbers) {
    return {
      valid: false,
      message: 'Password must contain uppercase, lowercase, and numbers'
    };
  }

  return { valid: true };
}

// Server-side hashing (Node.js example)
const bcrypt = require('bcrypt');
const saltRounds = 10;

// Hash password
const hashedPassword = await bcrypt.hash(password, saltRounds);

// Verify password
const match = await bcrypt.compare(password, hashedPassword);

4. Session Security

Best Practices:

  • Set session timeout
  • Clear session data on logout
  • Validate session on critical operations
  • Use secure session storage
// ✅ Session timeout
const SESSION_TIMEOUT = 30 * 60 * 1000; // 30 minutes
let sessionTimer;

function resetSessionTimer() {
  clearTimeout(sessionTimer);

  sessionTimer = setTimeout(() => {
    console.log('Session timeout - logging out');
    AuthManager.logout();
  }, SESSION_TIMEOUT);
}

// Reset timer on user activity
document.addEventListener('click', resetSessionTimer);
document.addEventListener('keypress', resetSessionTimer);

// Clear on logout
AuthManager.on('logout', () => {
  clearTimeout(sessionTimer);
});

5. API Security

Best Practices:

  • Use HTTPS
  • Validate inputs
  • Sanitize outputs
  • Use CORS properly
// ✅ HTTPS enforcement
if (location.protocol !== 'https:' && location.hostname !== 'localhost') {
  location.replace(`https:${location.href.substring(location.protocol.length)}`);
}

// ✅ CORS configuration (server-side example)
app.use(cors({
  origin: 'https://yourdomain.com',
  credentials: true,
  allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token']
}));

// ✅ Input validation
function validateLoginInput(credentials) {
  if (!credentials.username || !credentials.password) {
    throw new Error('Username and password are required');
  }

  // Email validation
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(credentials.username)) {
    throw new Error('Invalid email format');
  }

  return true;
}

Core Components

Guides

Browser Compatibility

Authentication System supports modern browsers:

  • ✅ Chrome 90+
  • ✅ Firefox 88+
  • ✅ Safari 14+
  • ✅ Edge 90+
  • ❌ IE 11 (not supported)

Required Features:

  • Promises & async/await
  • Fetch API
  • ES6+ features
  • httpOnly Cookies
  • Web Storage API

Performance Considerations

1. Token Validation

// ❌ Bad - validate on every request
if (!TokenService.isTokenExpired(token)) {
  // Make request
}

// ✅ Good - cache validation result
let tokenValid = true;
let lastCheck = Date.now();

function isTokenValid() {
  const now = Date.now();
  if (now - lastCheck > 60000) { // Check every minute
    tokenValid = !TokenService.isTokenExpired(token);
    lastCheck = now;
  }
  return tokenValid;
}

2. Minimize API Calls

// ❌ Bad - verify on every navigation
Router.on('beforeNavigate', async () => {
  await AuthManager.checkAuthStatus(); // Calls API every time
});

// ✅ Good - verify periodically
const VERIFY_INTERVAL = 5 * 60 * 1000; // 5 minutes
let lastVerify = Date.now();

Router.on('beforeNavigate', async () => {
  const now = Date.now();
  if (now - lastVerify > VERIFY_INTERVAL) {
    await AuthManager.checkAuthStatus();
    lastVerify = now;
  }
});

3. Optimize Storage

// ✅ Store minimal user data
const minimalUser = {
  id: user.id,
  name: user.name,
  email: user.email,
  roles: user.roles,
  permissions: user.permissions
};

AuthManager.setAuthenticatedUser(minimalUser);

// ❌ Don't store large objects
// AuthManager.setAuthenticatedUser(userWithAllData); // Too large!

Troubleshooting

1. Token Not Sent with Requests

Problem: Authorization header not sent with requests

Solution:

// Check if AuthManager initialized
console.log('Auth initialized:', AuthManager.isInitialized());

// Check if token exists
const token = TokenService.getToken();
console.log('Token exists:', !!token);

// Check HTTP interceptors
console.log('HttpClient interceptors:', httpClient.interceptors);

2. Infinite Redirect Loop

Problem: Redirect loop between login and dashboard

Solution:

// Check route configuration
await Router.init({
  routes: [
    {
      path: '/login',
      handler: 'login',
      metadata: {
        public: true,     // or guestOnly: true
        guestOnly: true   // Redirect to dashboard if authenticated
      }
    },
    {
      path: '/dashboard',
      handler: 'dashboard',
      metadata: {
        requiresAuth: true  // Redirect to login if not authenticated
      }
    }
  ]
});

3. Token Refresh Failed

Problem: Token refresh not successful

Solution:

// Check refresh token
const refreshToken = AuthManager.getRefreshToken();
console.log('Refresh token exists:', !!refreshToken);

// Check refresh endpoint
console.log('Refresh endpoint:', AuthManager.config.endpoints.refresh);

// Handle refresh failure
document.addEventListener('auth:refresh:failed', (e) => {
  console.error('Refresh failed:', e.detail);

  // Logout and redirect
  AuthManager.logout(false);
  Router.navigate('/login');
});

4. CSRF Token Missing

Problem: CSRF token not sent with requests

Solution:

// Check if CSRF enabled
console.log('CSRF enabled:', AuthManager.config.security.csrf);

// Check CSRF token
const csrfToken = AuthManager.getCSRFToken();
console.log('CSRF token:', csrfToken);

// Check meta tag
const metaTag = document.querySelector('meta[name="csrf-token"]');
console.log('Meta tag exists:', !!metaTag);
console.log('Meta tag content:', metaTag?.content);

Additional Resources

Examples

API References