@chabaduniverse/auth
v0.1.0
Published
Pluggable authentication library for ChabadUniverse applications with multiple provider support
Downloads
105
Readme
@chabaduniverse/auth
Pluggable authentication library for ChabadUniverse applications with multiple provider support
Features
- ✨ Multiple Authentication Methods: Bearer Token, Credentials, Google OAuth, Chabad.org SSO, Cross-Domain SSO
- 🔌 Adapter Pattern: Framework-agnostic core with pluggable adapters
- ⚛️ React Integration: Ready-to-use hooks and components
- 🎭 Dual Authentication: Simultaneous Valu Social + Merkos Platform authentication
- 🔒 Type-Safe: Full TypeScript support with comprehensive type definitions
- 🎨 Headless Components: UI-library independent with render props
- 📦 Tree-Shakeable: Modular design for optimal bundle sizes
- 🧪 Well Tested: Comprehensive test suite with 311 tests passing (83%+ coverage)
- 📚 Fully Documented: Complete API documentation and integration guides
Installation
npm install @chabaduniverse/authPeer Dependencies
For React applications:
npm install react react-domQuick Start
1. Set Up Authentication Provider
import { AuthProvider } from '@chabaduniverse/auth/react';
import { MerkosAPIAdapter } from '@chabaduniverse/auth/adapters';
// Create adapter
const merkosAdapter = new MerkosAPIAdapter({
baseUrl: 'https://org.merkos302.com',
apiVersion: 'v2',
});
// Configure provider
const authConfig = {
apiAdapter: merkosAdapter,
userServiceAdapter: yourUserService,
};
function App() {
return (
<AuthProvider config={authConfig}>
<YourApp />
</AuthProvider>
);
}2. Use Authentication in Components
import { useAuth } from '@chabaduniverse/auth/react';
function Dashboard() {
const { isAuthenticated, user, loginWithBearerToken, logout } = useAuth();
if (!isAuthenticated) {
return <button onClick={() => loginWithBearerToken('token')}>Login</button>;
}
return (
<div>
<h2>Welcome, {user?.name}!</h2>
<button onClick={logout}>Logout</button>
</div>
);
}3. Protect Routes
import { AuthGuard, BearerTokenDialog } from '@chabaduniverse/auth/react';
function ProtectedPage() {
return (
<AuthGuard
requireMerkosAuth
BearerTokenDialog={BearerTokenDialog}
>
<YourProtectedContent />
</AuthGuard>
);
}Core Concepts
Adapter Pattern
All external dependencies are abstracted through adapter interfaces:
interface AuthAPIAdapter {
loginWithBearerToken(token: string): Promise<AuthResponse>;
loginWithCredentials(username: string, password: string): Promise<AuthResponse>;
loginWithGoogle(code: string): Promise<AuthResponse>;
getCurrentUser(): Promise<User>;
logout(): Promise<void>;
// ... more methods
}This allows you to:
- Switch between API implementations without changing your code
- Mock adapters for testing
- Use custom API clients
- Support multiple backends
Dual Authentication
Support for simultaneous Valu Social and Merkos Platform authentication:
import { useAuth, useValuAuth } from '@chabaduniverse/auth/react';
function Component() {
const { isAuthenticated: merkosAuth } = useAuth();
const { isAuthenticated: valuAuth, isInValuFrame } = useValuAuth();
// Handle both authentication states
}Headless Components
UI components use render props for maximum flexibility:
<BearerTokenDialog
open={open}
onTokenSubmit={handleSubmit}
render={({ token, setToken, handleSubmit, isLoading }) => (
<YourCustomUI />
)}
/>API Reference
Hooks
useAuth()
Main authentication hook providing state and methods:
const {
// State
isAuthenticated,
isLoading,
isInitialized,
user,
error,
hasMerkosBearerToken,
// Methods
loginWithBearerToken,
loginWithCredentials,
loginWithGoogle,
loginWithChabadOrg,
loginWithCDSSO,
logout,
refreshAuth,
} = useAuth();useValuAuth()
Valu Social authentication hook:
const {
user,
isAuthenticated,
isInValuFrame,
isConnected,
getUserIcon,
refreshUser,
} = useValuAuth();Components
<AuthProvider>
Root authentication provider component.
Props:
config- Authentication configuration with adapters
<AuthGuard>
Route protection component with automatic bearer token prompt.
Props:
children- Protected contentrequireMerkosAuth- Require Merkos authenticationrequireValuAuth- Require Valu authenticationBearerTokenDialog- Optional custom dialog componentfallback- Loading/unauthorized fallback UI
<BearerTokenDialog>
Headless bearer token input dialog.
Props:
open- Dialog open stateonOpenChange- State change callbackonTokenSubmit- Token submission handlerrender- Optional custom render function
Adapters
MerkosAPIAdapter
Merkos Platform API v2 adapter implementation with comprehensive authentication support.
const adapter = new MerkosAPIAdapter({
baseUrl: 'https://org.merkos302.com',
apiVersion: 'v2',
timeout: 30000,
});Phase 5A Implementation (Completed):
- ✅
setToken(token: string): void- Token storage for authenticated requests - ✅
clearToken(): void- Token cleanup on logout - ✅
v2Request<T>(service, path, params): Promise<T>- Core v2 API request method
Phase 5B Implementation (Completed):
- ✅
loginWithBearerToken(token, siteId?): Promise<AuthResponse>- Bearer token authentication - ✅
loginWithCredentials(username, password, siteId?): Promise<AuthResponse>- Username/password login - ✅
loginWithGoogle(code, host?, siteId?): Promise<AuthResponse>- Google OAuth login - ✅
loginWithChabadOrg(key, siteId?): Promise<AuthResponse>- Chabad.org SSO login
Phase 5C Implementation (Completed):
- ✅
getCurrentUser(): Promise<User>- Retrieve authenticated user information - ✅
logout(): Promise<void>- End user session and clear tokens
Features:
- Unified POST
/api/v2endpoint for all requests - Custom
identifierheader for authentication (notAuthorization) - Intelligent error code mapping (Merkos errors → AuthErrorCode enum)
- AbortController-based timeout handling
- Type-safe generic responses
- Comprehensive error detection (API errors, network errors, timeouts)
- Four complete authentication methods with full error handling
Quick Example:
import { MerkosAPIAdapter } from '@chabaduniverse/auth/adapters';
import { AuthError, AuthErrorCode } from '@chabaduniverse/auth';
const adapter = new MerkosAPIAdapter({
baseUrl: 'https://org.merkos302.com',
});
// Login with credentials
try {
const response = await adapter.loginWithCredentials(
'[email protected]',
'password'
);
console.log('Logged in as:', response.user.name);
} catch (error) {
if (error instanceof AuthError) {
if (error.code === AuthErrorCode.INVALID_CREDENTIALS) {
console.error('Invalid username or password');
}
}
}For comprehensive usage examples, see MerkosAPIAdapter Examples.
Database Models
Six MongoDB models for complete user data management:
User- Core user authenticationProfile- User profile dataPreferences- User preferences and settingsActivity- User activity trackingAppData- App-specific data storageAnalytics- User engagement analytics
Package Exports
// Core (framework-agnostic)
import { AuthManager, TokenStorage } from '@chabaduniverse/auth';
// React bindings
import { AuthProvider, useAuth, AuthGuard } from '@chabaduniverse/auth/react';
// Adapters
import { MerkosAPIAdapter } from '@chabaduniverse/auth/adapters';
// Database models
import { User, Profile, Preferences } from '@chabaduniverse/auth/database';Documentation
- 📘 Integration Guide - Complete integration walkthrough
- 🚀 Quick Start Guide - Get started in 5 minutes
- 📖 API Documentation - Detailed API reference
- 🔄 Migration Guide - Migrate from universe-portal
- 🔌 MerkosAPIAdapter Examples - Merkos Platform API adapter usage
Examples
Next.js Integration
// pages/_app.tsx
import { AuthProvider } from '@chabaduniverse/auth/react';
import { MerkosAPIAdapter } from '@chabaduniverse/auth/adapters';
const merkosAdapter = new MerkosAPIAdapter({ baseUrl: process.env.API_URL });
function MyApp({ Component, pageProps }) {
return (
<AuthProvider config={{ apiAdapter: merkosAdapter, userServiceAdapter }}>
<Component {...pageProps} />
</AuthProvider>
);
}Custom UI with shadcn/ui
import { BearerTokenDialog } from '@chabaduniverse/auth/react';
import { Dialog, DialogContent, Input, Button } from '@/components/ui';
<BearerTokenDialog
open={open}
onTokenSubmit={handleSubmit}
render={({ token, setToken, handleSubmit, isLoading, inputRef }) => (
<Dialog open onOpenChange={handleCancel}>
<DialogContent>
<Input
ref={inputRef}
type="password"
value={token}
onChange={(e) => setToken(e.target.value)}
/>
<Button onClick={handleSubmit} disabled={isLoading}>
Submit
</Button>
</DialogContent>
</Dialog>
)}
/>Testing
import { render } from '@testing-library/react';
import { AuthProvider, useAuth } from '@chabaduniverse/auth/react';
import { mockAdapter } from './mocks';
test('authentication flow', async () => {
const { result } = renderHook(() => useAuth(), {
wrapper: ({ children }) => (
<AuthProvider config={{ apiAdapter: mockAdapter }}>
{children}
</AuthProvider>
),
});
await act(() => result.current.loginWithBearerToken('token'));
expect(result.current.isAuthenticated).toBe(true);
});Browser Support
- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- React 16.8+ (hooks support required)
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
MIT © ChabadUniverse Team
Support
- 📧 Email: [email protected]
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
Made with ❤️ by the ChabadUniverse Team
