Now.js Framework Documentation
Authentication System
Authentication System
Overview documentation for the Now.js Framework Authentication System
📋 Table of Contents
- Overview
- System Architecture
- Core Components
- Quick Start
- Authentication Flows
- Usage Examples
- Best Practices
- Security Considerations
- 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
-
User Login:
User → AuthManager.login() → API → Response (JWT) → TokenService.store() → HttpOnly Cookie → AuthManager.setAuthenticatedUser() → Update State -
Protected Route Access:
Router → AuthGuard.checkRoute() → AuthManager.checkAuthStatus() → TokenService.getToken() → Validate Token → Check Permissions/Roles → Allow/Deny -
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 automaticallyAuthentication 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:
AuthLoadingManagershows loading overlayAuthManagercalls login endpoint- Server validates credentials
- Server sends JWT tokens back
TokenServicestores access token in httpOnly cookieTokenServicestores refresh token in httpOnly cookie (if available)AuthManagerstores user data in localStorageAuthManagerupdates state (authenticated = true)AuthManagerredirects toafterLoginrouteAuthLoadingManagerhides 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:
- Router calls
AuthGuard.checkRoute() AuthGuardcallsAuthManager.checkAuthStatus()AuthManagerchecks authentication status- If token exists but not verified → call verify endpoint
AuthGuardchecks roles and permissions- If passed → allow navigation
- 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:
AuthManagersets timer 5 minutes before token expires- Timer triggers → call
refreshToken() TokenServicereads refresh token from cookieAuthManagercalls refresh endpoint with refresh token- Server validates refresh token
- Server sends new access token back
TokenServicestores new access tokenAuthManagersets 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 invalidFORBIDDEN- No permission to accessTOKEN_EXPIRED- Token expiredTOKEN_INVALID- Token is invalidSESSION_EXPIRED- Session expiredRATE_LIMITED- Too many requestsACCOUNT_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 XSS2. 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;
}Related Documentation
Core Components
- AuthManager.md - Core authentication manager
- TokenService.md - JWT token management
- AuthGuard.md - Route protection
- AuthErrorHandler.md - Error handling
- AuthLoadingManager.md - Loading states
Related Systems
- Router.md - Routing system (works with AuthGuard)
- ApiService.md - HTTP service (auto-includes auth tokens)
- HttpClient.md - Low-level HTTP client
Guides
- Quick Start Guide - Quick start guide
- Social Login Guide - Social login setup
- Security Best Practices - Security guidelines
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
- Complete Login Example - Complete login form
- Protected Routes Example - Route protection
- Social Login Example - Social login integration
- Role-Based UI Example - Show/hide UI based on role
API References
- Server API Specification - Auth endpoints specification
- JWT Structure - JWT payload structure
- Error Codes - Error codes and messages