Package Exports
- exguard-client
- exguard-client/setup
Readme
exguard-client
ExGuard RBAC (Role-Based Access Control) client library with realtime WebSocket support for EmpowerX applications.
📦 Public Package: Available on npm for easy integration into React applications.
Features
- 🔐 RBAC Authentication: Token verification and user access management
- 🔄 Realtime Updates: WebSocket-based real-time RBAC changes
- 🎯 Permission Guards: React components for route and feature protection
- 🪝 React Hooks: Easy-to-use hooks for permission checking
- 📦 TypeScript: Full type safety with TypeScript definitions
- ⚡ Auto-Configuration: Automatically detects API URL based on environment
- 🚀 Zero Setup: Works out of the box with sensible defaults
- 💾 Smart Caching: localStorage persistence for user access data, survives page refreshes, auto-invalidates on permission changes
Documentation
- FRONTEND_INTEGRATION_GUIDE.md - Step-by-step integration guide (START HERE)
- PAGE_IMPLEMENTATION_GUIDE.md - Advanced page protection patterns
- IMPLEMENTATION_GUIDE.md - Technical implementation details
Installation
pnpm add exguard-clientAutomated Setup (Recommended)
Run the setup command to automatically configure your project:
pnpm exec exguard-setupThis will:
- ✅ Create
src/features/exguard/module structure - ✅ Update
protected-route.tsxto wrap<Outlet />withExGuardRealtimeProvider - ✅ Update
auth-utils.tswith token event dispatch
Result in your protected-route.tsx:
return (
<ExGuardRealtimeProvider>
<Outlet />
</ExGuardRealtimeProvider>
);Then skip to Step 3 in FRONTEND_INTEGRATION_GUIDE.md!
Peer Dependencies
Make sure you have the required peer dependencies installed:
pnpm add react react-dom react-router axios socket.io-clientQuick Start
1. Add Provider to Protected Route
In your protected-route.tsx:
import { ExGuardRealtimeProvider } from '@/features/exguard';
return (
<ExGuardRealtimeProvider>
<Outlet />
</ExGuardRealtimeProvider>
);That's it! The package automatically:
- Connects to ExGuard WebSocket when user is authenticated
- Detects API URL based on your hostname (localhost → http://localhost:3000, production → https://yourdomain.com/api)
- Reads auth tokens from localStorage/sessionStorage
- Provides RBAC context to all protected routes
2. Use Permission Guards
import { PermissionGuard } from '@/features/exguard';
<PermissionGuard module="EXID">
<ProfilesPage />
</PermissionGuard>3. Check Permissions in Components
import { useUserAccess } from '@/features/exguard';
function MyComponent() {
const { hasModuleAccess, hasPermission } = useUserAccess();
return (
<div>
{hasModuleAccess('EXID') && <div>EXID Module</div>}
{hasPermission('EXID', 'profile:create') && <button>Create</button>}
</div>
);
}4. Caching (localStorage)
The package automatically caches /guard/me responses for 5 minutes with localStorage persistence:
- localStorage Persistence: Data survives page refreshes
- Single API Call: First call fetches data, subsequent calls use cache
- Auto-Invalidation: Cache clears automatically when permissions change via WebSocket
- No Manual Management: Works out of the box
Manual Cache Control (if needed):
import { useUserAccessSingleton } from '@/features/exguard';
function MyComponent() {
const { refetch, invalidateCache, clearCache, isLoading } = useUserAccessSingleton();
// Force refetch (bypasses cache)
const handleRefresh = async () => {
await refetch(true);
};
// Manual cache bust + refetch
const handleForceRefresh = () => {
invalidateCache();
refetch();
};
}Clear Cache on Logout:
import { clearUserAccessCache } from 'exguard-client';
function LogoutButton() {
const handleLogout = async () => {
// Clear ExGuard cache first
clearUserAccessCache();
// Then perform your app logout
await logout();
navigate('/login');
};
return <button onClick={handleLogout}>Logout</button>;
}📖 For complete examples and advanced usage, see FRONTEND_INTEGRATION_GUIDE.md
3. Optional: Custom Configuration
Only needed if you want to override defaults:
import { setExGuardConfig, ExGuardRealtimeProvider } from 'exguard-client';
// Optional: Override auto-detection
setExGuardConfig({
apiUrl: 'https://custom-api.example.com',
getAuthToken: () => localStorage.getItem('custom_token_key')
});
<ExGuardRealtimeProvider>
<App />
</ExGuardRealtimeProvider>Auto-Configuration
The package automatically configures itself based on your environment:
API URL Detection (Priority Order)
- Manual Configuration:
setExGuardConfig({ apiUrl: '...' }) - Environment Variables:
- Vite:
VITE_GUARD_APP_URL - Next.js:
NEXT_PUBLIC_GUARD_APP_URL - Window:
window.__EXGUARD_API_URL__
- Vite:
- Auto-Detection:
- localhost/127.0.0.1 →
http://localhost:3000 - Other domains →
${protocol}//${hostname}/api
- localhost/127.0.0.1 →
Authentication Token
Automatically reads from:
- Custom getter if provided via
setExGuardConfig localStorage.getItem('access_token')sessionStorage.getItem('access_token')
4. Use ExGuard Components
import { PermissionGuard, useUserAccess } from '@/features/exguard';
// Route protection
<PermissionGuard module="EXID">
<ProfilesPage />
</PermissionGuard>
// Permission checking
function MyComponent() {
const { hasModuleAccess, hasPermission } = useUserAccess();
return (
<div>
{hasModuleAccess('EXID') && <div>EXID Module</div>}
{hasPermission('EXID', 'profile:create') && <button>Create</button>}
</div>
);
}API Reference
Configuration
setExGuardConfig(config)
Configure the ExGuard API URL and other settings.
import { setExGuardConfig } from 'exguard-client';
setExGuardConfig({
apiUrl: 'https://your-exguard-api.com',
withCredentials: true, // default: true
});Components
ExGuardRealtimeProvider
Provider component that manages WebSocket connections and RBAC state.
<ExGuardRealtimeProvider>
{/* Your app */}
</ExGuardRealtimeProvider>PermissionGuard
Route guard component for RBAC permission checking.
<PermissionGuard
module="EXID" // Required: Module key
permission="profile:create" // Optional: Specific permission
requireModule={true} // Optional: Require module access (default: true)
requirePermission={true} // Optional: Require permission (default: true if permission provided)
fallbackPath="/unauthorized" // Optional: Redirect path on access denied
>
<YourProtectedComponent />
</PermissionGuard>Hooks
useUserAccess(options?)
Hook to fetch and manage user access data with RBAC. Uses singleton pattern with caching.
const {
userAccess, // Full user access data
isLoading, // Loading state
error, // Error state
hasModuleAccess, // Function to check module access
hasPermission, // Function to check specific permission
} = useUserAccess({
enabled: true, // Optional: Enable/disable fetching (default: true)
refetchInterval: 30000, // Optional: Refetch interval in ms (default: 0, uses cache)
});Caching Behavior:
- Caches response for 5 minutes
- Multiple components share the same cached data
- Cache auto-invalidates when WebSocket sends
user:access-changedevent - Set
refetchInterval> 0 to force periodic refetches
Methods:
hasModuleAccess(moduleKey: string): boolean- Check if user has access to a modulehasPermission(moduleKey: string, permission: string): boolean- Check if user has a specific permission
useUserAccessSingleton()
Singleton hook for accessing user access data with localStorage caching. Best for components that need user info (e.g., layout, sidebar).
const {
userAccess, // Full user access data
isLoading, // Loading state
isFetching, // Currently fetching (including cache checks)
error, // Error state
refetch, // Function to refetch (accepts force param)
refetchSilent, // Refetch without loading state
invalidateCache, // Manually invalidate memory cache
clearCache, // Clear localStorage cache
} = useUserAccessSingleton();
// Refetch with cache (uses cached data if < 5 min old)
await refetch();
// Force refetch (ignores cache)
await refetch(true);
// Manual cache control
invalidateCache();
await refetch();When to use:
useUserAccessSingleton- Layouts, headers, sidebars (single user context)useUserAccess- Feature components, pages (isolated usage)
Note: The hook uses localStorage for persistence. On page load, it first checks localStorage for cached data before making an API call. This provides instant access to user data even on first render after page refresh.
useExGuardRealtime()
Hook to access the ExGuard realtime context.
const {
isConnected, // WebSocket connection state
registerRbacRefreshCallback, // Register callback for RBAC updates
} = useExGuardRealtime();useExGuardRealtimeSubscription(eventType, handler)
Hook to subscribe to specific realtime events.
import { useExGuardRealtimeSubscription, EXGUARD_RBAC_EVENTS } from 'exguard-client';
useExGuardRealtimeSubscription(
EXGUARD_RBAC_EVENTS.RBAC_PERMISSIONS_UPDATED,
(payload) => {
console.log('Permissions updated:', payload);
// Handle the event
}
);API Functions
clearUserAccessCache()
Clear the cached user access data from localStorage. Call this on logout.
import { clearUserAccessCache } from 'exguard-client';
async function handleLogout() {
// Clear ExGuard cache
clearUserAccessCache();
// Perform app logout
await logout();
navigate('/login');
}verifyToken()
Verify the current ID token with the ExGuard backend.
import { verifyToken } from 'exguard-client';
const result = await verifyToken();
if (result.isValid && result.user) {
console.log('User:', result.user);
}getUserAccess()
Fetch the current user's access data (roles, permissions, modules).
import { getUserAccess } from 'exguard-client';
const userAccess = await getUserAccess();
console.log('Modules:', userAccess.modules);
console.log('Roles:', userAccess.roles);Constants
EXGUARD_RBAC_EVENTS
Constants for ExGuard RBAC event types.
import { EXGUARD_RBAC_EVENTS } from 'exguard-client';
// Available events:
EXGUARD_RBAC_EVENTS.ROLE_CREATED
EXGUARD_RBAC_EVENTS.ROLE_UPDATED
EXGUARD_RBAC_EVENTS.ROLE_DELETED
EXGUARD_RBAC_EVENTS.PERMISSION_CREATED
EXGUARD_RBAC_EVENTS.PERMISSION_UPDATED
EXGUARD_RBAC_EVENTS.PERMISSION_DELETED
EXGUARD_RBAC_EVENTS.USER_ROLES_UPDATED
EXGUARD_RBAC_EVENTS.USER_PERMISSIONS_CHANGED
EXGUARD_RBAC_EVENTS.USER_ACCESS_CHANGED
EXGUARD_RBAC_EVENTS.RBAC_PERMISSIONS_UPDATED
// ... and moreEXGUARD_STORAGE_KEYS
Constants for localStorage keys used by ExGuard.
import { EXGUARD_STORAGE_KEYS } from 'exguard-client';
// Available keys:
EXGUARD_STORAGE_KEYS.ACCESS_TOKEN
EXGUARD_STORAGE_KEYS.ID_TOKEN
EXGUARD_STORAGE_KEYS.REFRESH_TOKENTypes
The package exports all necessary TypeScript types:
import type {
UserAccessData,
ModulePermissions,
UserDetails,
VerifyTokenResponse,
RealtimeEventType,
RealtimeEventPayload,
ExGuardConfig,
} from 'exguard-client';Environment Variables
The package automatically detects environment variables in consuming applications:
Vite
VITE_GUARD_APP_URL=https://your-exguard-api.comNext.js
NEXT_PUBLIC_GUARD_APP_URL=https://your-exguard-api.comOr set it programmatically using setExGuardConfig().
Storage
ExGuard uses localStorage for token management and user access caching:
Authentication Tokens
access_token- Access token for API authenticationid_token- ID token for user verificationrefresh_token- Refresh token for token renewal
Cached Data
exguard_user_access- Cached user access data (roles, permissions, modules)exguard_user_access_timestamp- Cache timestamp for TTL validation
The cache persists for 5 minutes and is automatically invalidated when:
- User permissions change via WebSocket
- You call
invalidateCache()orclearUserAccessCache()
Security: Data is obfuscated using XOR cipher + base64 encoding to prevent casual reading of localStorage data.
License
MIT
Support
For issues or questions, please contact the EmpowerX development team.