@crystaltech/shared-auth
v0.5.3
Published
A shared authentication module for Crystal HIS applications using Keycloak, providing comprehensive authentication, authorization, and organization-specific access control.
Readme
@crystaltech/shared-auth
A shared authentication module for Crystal HIS applications using Keycloak, providing comprehensive authentication, authorization, and organization-specific access control.
Installation
npm install @crystaltech/shared-authQuick Start
import { AuthProvider, LoginComponent } from '@crystaltech/shared-auth';
const App = () => {
return (
<AuthProvider backendUrl="your-backend-url">
<LoginComponent
onLoginSuccess={() => console.log('Login successful')}
onLoginError={(error) => console.error('Login failed:', error)}
/>
</AuthProvider>
);
};Core Components
AuthProvider
The root component that provides authentication context to your application. It handles token management, automatic token refresh, user session management, and displays session expiration notifications.
import { AuthProvider } from '@crystaltech/shared-auth';
const App = () => {
return (
<AuthProvider
backendUrl="your-backend-url"
autoRelogin={true}
cleanupOptions={{
scope: 'conservative', // 'conservative' | 'full'
clearStorage: true,
clearCaches: false,
clearIndexedDB: true,
clearServiceWorkers: false,
storageKeys: ['custom_key'] // Optional custom keys to clear
}}
// The AuthProvider will automatically handle:
// - Token management
// - Automatic token refresh
// - User session management
// - SSO integration
// - Session expiration UI notifications
// - Enhanced error handling with detailed context
>
{/* Your app components */}
</AuthProvider>
);
};Session Expiration UI Banner
The AuthProvider automatically displays a Material-UI banner when the user's session expires, providing:
- Auto-hide: Banner disappears after 8 seconds
- Re-open logic: Reappears after 30 seconds if session is still expired and not dismissed
- Action buttons: "Sign in" and "Dismiss" options
- Error details: Sanitized error information including URL and status
- Non-intrusive: Positioned at top-center with warning styling
The banner integrates seamlessly with your app's Material-UI theme and provides a smooth user experience during authentication issues.
Cleanup Options
Configure how the AuthProvider cleans up application state during logout:
interface CleanupOptions {
scope?: 'conservative' | 'full'; // Cleanup scope
clearStorage?: boolean; // Clear localStorage/sessionStorage
clearCaches?: boolean; // Clear browser caches
clearIndexedDB?: boolean; // Clear IndexedDB
clearServiceWorkers?: boolean; // Unregister service workers
storageKeys?: string[]; // Custom storage keys to clear
}- Conservative (default): Clears only authentication-related data
- Full: Performs comprehensive cleanup including caches and service workers
LoginComponent
A Material-UI based login component with customizable UI and behavior. Supports custom styling and event handlers.
import { LoginComponent } from '@crystaltech/shared-auth';
const Login = () => {
return (
<LoginComponent
// Event Handlers
onLoginSuccess={(userInfo) => console.log('Login successful:', userInfo)}
onLoginError={(error) => console.error('Login failed:', error)}
// UI Customization
title="Welcome Back"
loginButtonText="Sign In"
logoutButtonText="Sign Out"
welcomeText="Hello"
// Styling
containerSx={{ mt: 4 }}
paperSx={{ p: 4 }}
loginButtonProps={{
size: 'large',
variant: 'contained',
color: 'primary'
}}
logoutButtonProps={{
size: 'large',
variant: 'outlined',
color: 'error'
}}
/>
);
};AuthButton
A simple, flexible authentication button component for login/logout actions. Perfect for navigation bars and headers.
import { AuthButton } from '@crystaltech/shared-auth';
const Header = () => {
return (
<AuthButton
onLoginClick={() => {
console.log('Login clicked');
// Additional login logic
}}
onLogoutClick={() => {
console.log('Logout clicked');
// Cleanup or redirect logic
}}
className="auth-button"
/>
);
};ProtectedRoute
A component that protects routes based on authentication status and optional role requirements.
import { ProtectedRoute } from '@crystaltech/shared-auth';
const App = () => {
return (
<Router>
<Routes>
{/* Basic Protection */}
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
{/* Role-Based Protection */}
<Route
path="/admin"
element={
<ProtectedRoute requiredRoles={['admin']}>
<AdminDashboard />
</ProtectedRoute>
}
/>
{/* Custom Redirect */}
<Route
path="/reports"
element={
<ProtectedRoute
redirectPath="/custom-login"
fallback={<CustomLoadingComponent />}
>
<Reports />
</ProtectedRoute>
}
/>
</Routes>
</Router>
);
};Authentication Hook
useAuth
A powerful custom hook that provides access to authentication state and methods.
import { useAuth } from '@crystaltech/shared-auth';
const UserProfile = () => {
const {
userInfo, // Current user information
token, // Current access token
authenticated, // Authentication status
login, // Initiate login
logout, // Logout user
validateToken, // Validate current token
refreshTokenWithBackend, // Force token refresh
getUserProfile, // Fetch user profile
getToken // Get current token
} = useAuth();
// Authentication Status Check
if (!authenticated) {
return <button onClick={login}>Login</button>;
}
// Role-Based Rendering
const isAdmin = userInfo?.realm_access?.roles?.includes('admin');
return (
<div>
<h1>Welcome, {userInfo?.name}</h1>
{isAdmin && <AdminPanel />}
<button onClick={logout}>Logout</button>
</div>
);
};API Client Integration
The apiClient utility provides a pre-configured Axios instance for making authenticated API requests with automatic token management and enhanced error handling.
import { apiClient } from '@crystaltech/shared-auth';
// Configure API client
const api = apiClient({
baseURL: 'your-backend-url',
timeout: 5000,
headers: {
'Custom-Header': 'value'
},
onUnauthorized: (error) => {
// Optional callback for unauthorized errors
console.log('Unauthorized access detected:', error);
}
});
// Making authenticated requests
const fetchData = async () => {
try {
// GET request
const { data: users } = await api.get('/api/users');
// POST request
const { data: newUser } = await api.post('/api/users', {
name: 'John Doe',
email: '[email protected]'
});
// PUT request
await api.put(`/api/users/${userId}`, updatedData);
// DELETE request
await api.delete(`/api/users/${userId}`);
return data;
} catch (error) {
console.error('API request failed:', error);
throw error;
}
};Enhanced Error Handling
The API client automatically handles authentication errors with:
- Automatic Token Refresh: Seamlessly refreshes expired tokens
- Request Retry: Retries failed requests with new tokens
- Global Event Dispatch: Triggers
shared-auth:unauthorizedevents - Enhanced Error Context: Includes URL, status, and error details
- Fallback Handling: Graceful degradation when refresh fails
Unauthorized Event Handling
Listen for authentication events in your application:
// Listen for unauthorized events
window.addEventListener('shared-auth:unauthorized', (event) => {
const { error, url, status } = event.detail;
console.log('Unauthorized access:', {
url, // The URL that failed
status, // HTTP status code
error // Error details
});
// Handle the unauthorized access
// - Show notification
// - Redirect to login
// - Log analytics event
});Type Definitions
UserInfo
interface UserInfo {
sub?: string; // Subject identifier
email?: string; // User's email
name?: string; // Full name
preferred_username?: string; // Preferred username
given_name?: string; // First name
family_name?: string; // Last name
realm_access?: {
roles?: string[]; // Realm-level roles
};
resource_access?: {
account?: {
roles?: string[]; // Resource-specific roles
};
};
}AuthResponse
interface AuthResponse {
accessToken: string; // JWT access token
refreshToken: string; // Refresh token
expiresIn: number; // Token expiration time in seconds
tokenType: string; // Token type (e.g., "Bearer")
scope?: string; // Token scope
idToken?: string; // OpenID Connect ID token
sessionState?: string; // Session state
}ApiClientConfig
interface ApiClientConfig {
baseURL: string; // Base URL for API requests
timeout?: number; // Request timeout in milliseconds
headers?: Record<string, string>; // Custom headers
}Features
๐ Secure Authentication with Keycloak
- OAuth 2.0 and OpenID Connect compliant
- Automatic token refresh
- Session management
- Enhanced error handling with detailed context
๐จ Material-UI Components
- Customizable login interface
- Session expiration UI banner with auto-hide/re-open
- Responsive design
- Theme support
๐ TypeScript Support
- Full type definitions
- Type-safe hooks and components
- IntelliSense support
๐ Advanced Token Management
- Automatic token refresh
- Token validation
- Secure storage
- Request retry on token refresh
๐ SSO Integration
- Single Sign-On support
- Silent token refresh
- Cross-domain authentication
๐ฅ Multi-tenancy Support
- Organization-specific authentication
- Role-based access control
- Custom claims support
๐ Role-Based Access Control (RBAC)
- Fine-grained authorization
- Role-based route protection
- Permission-based rendering
๐ก๏ธ Protected Routes
- Authentication-based protection
- Role-based protection
- Custom redirect handling
๐ฏ Authentication Hooks
- Easy state management
- Authentication utilities
- Type-safe interfaces
- Session expiration state
๐ Enhanced API Integration
- Pre-configured API client
- Automatic token injection
- Advanced error handling
- Global unauthorized event dispatch
- Request retry mechanism
๐งน Configurable Cleanup
- Conservative and full cleanup modes
- Custom storage key management
- IndexedDB and cache clearing
- Service worker management
๐ User Experience
- Non-intrusive session expiration notifications
- Actionable error messages with dismiss/sign-in options
- Seamless token refresh without user interruption
Changelog
Version 0.4.3-alpha-0
๐ New Features
- Session Expiration UI Banner: Automatic Material-UI banner for session expiration with dismiss and sign-in actions
- Enhanced Error Handling: Improved
handleUnauthorizedwith sanitized error messages including URL and status details - Configurable Cleanup Options: Added
CleanupOptionsfor customizable logout cleanup behavior
๐ง Improvements
- Unauthorized Event Enhancement: Added
urlandstatustoshared-auth:unauthorizedevent payload - Login Callback Optimization: Improved effect dependencies to prevent unnecessary re-runs
- Error Context: Better error reporting with request context and sanitized messages
๐ Bug Fixes
- Fixed unused parameters in
handleUnauthorizedfunction - Improved token refresh flow reliability
- Enhanced error message sanitization for security