diff --git a/docs/01-architecture/authentication-architecture.md b/docs/01-architecture/authentication-architecture.md new file mode 100644 index 0000000..d0c3b8d --- /dev/null +++ b/docs/01-architecture/authentication-architecture.md @@ -0,0 +1,235 @@ +# Authentication Architecture + +This document describes the current authentication architecture using dependency injection and service-based patterns. + +## Overview + +The authentication system has been refactored from a legacy global composable approach to a modern dependency injection pattern. This eliminates timing issues, improves maintainability, and provides a single source of truth for authentication state. + +## Architecture Components + +### 1. AuthService (Core Service) +**Location**: `src/modules/base/auth/auth-service.ts` + +The `AuthService` is a singleton service that extends `BaseService` and provides: +- Reactive authentication state management +- LNBits API integration +- Event-driven authentication lifecycle +- Automatic token management + +**Key Features**: +```typescript +export class AuthService extends BaseService { + // Public reactive state + public isAuthenticated = ref(false) + public user = ref(null) + public isLoading = ref(false) + public error = ref(null) + + // Computed properties for compatibility + public currentUser = computed(() => this.user.value) + public userDisplay = computed(() => { /* user display logic */ }) + + // Methods + async login(credentials: LoginCredentials): Promise + async register(data: RegisterData): Promise + async logout(): Promise + async checkAuth(): Promise + async updatePassword(current: string, newPass: string): Promise + async updateProfile(data: Partial): Promise +} +``` + +### 2. useAuthService Composable (API Layer) +**Location**: `src/composables/useAuthService.ts` + +The `useAuthService` composable provides a clean, unified API that bridges Vue components with the injected AuthService: + +```typescript +export function useAuth() { + const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as AuthService + + return { + // State (reactive refs from service) + currentUser: authService.currentUser, + isAuthenticated: authService.isAuthenticated, + isLoading: authService.isLoading, + error: authService.error, + userDisplay: authService.userDisplay, + + // Methods (delegated to service) + initialize: () => authService.initialize(), + login: (credentials: any) => authService.login(credentials), + register: (data: any) => authService.register(data), + logout: () => authService.logout(), + checkAuth: () => authService.checkAuth() + } +} +``` + +### 3. Dependency Injection Container +**Location**: `src/core/di-container.ts` + +The DI container manages service registration and injection: + +```typescript +// Service registration (in base module) +container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService) + +// Service consumption (in components/other services) +const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) as AuthService +``` + +## Usage Patterns + +### In Vue Components (Recommended) +```vue + +``` + +### In Services (Direct Injection) +```typescript +import { injectService, SERVICE_TOKENS } from '@/core/di-container' +import type { AuthService } from '@/modules/base/auth/auth-service' + +export class SomeService extends BaseService { + private get authService(): AuthService { + return this.dependencies.get('AuthService') as AuthService + } + + async someMethod() { + const user = this.authService.user.value + if (user?.pubkey) { + // Use authenticated user data + } + } +} +``` + +## Benefits of New Architecture + +### 1. **Single Source of Truth** +- All authentication state managed by AuthService singleton +- No more timing issues between global and injected auth +- Consistent state across all modules and components + +### 2. **Dependency Injection Benefits** +- Loose coupling between components and auth logic +- Easy to test (can inject mock services) +- Modular architecture with clear boundaries +- Service lifecycle management + +### 3. **Improved Maintainability** +- Centralized authentication logic +- Event-driven architecture for auth state changes +- Clear separation of concerns +- Eliminated complex dual-auth detection patterns + +### 4. **Performance Improvements** +- No duplicate service instances +- Efficient reactive state management +- Reduced complexity in components + +## Migration Guide + +### Before (Legacy Pattern) +```typescript +// ❌ Old global composable pattern +import { auth } from '@/composables/useAuth' + +// Direct access to global singleton +const isAuthenticated = auth.isAuthenticated.value +``` + +### After (Current Pattern) +```typescript +// ✅ New dependency injection pattern +import { useAuth } from '@/composables/useAuthService' + +const auth = useAuth() +const isAuthenticated = auth.isAuthenticated.value +``` + +## Service Integration + +### Module Registration +Each module that needs authentication access should: + +1. **Declare dependency** on AuthService in module metadata +2. **Access via dependency injection** using the DI container +3. **Use reactive state** from the service for UI updates + +### Example Service Integration +```typescript +export class ChatService extends BaseService { + protected readonly metadata = { + name: 'ChatService', + dependencies: ['AuthService'] // Declare dependency + } + + async sendMessage(content: string) { + // Access auth through DI + const user = this.authService.user.value + if (!user?.pubkey || !user?.prvkey) { + throw new Error('Authentication required for messaging') + } + + // Use authenticated user data + const encrypted = await nip04.encrypt(user.prvkey, recipientPubkey, content) + // ... rest of implementation + } +} +``` + +## Error Handling + +The authentication system provides comprehensive error handling: + +1. **Network Errors**: Handled in AuthService with proper error propagation +2. **Invalid Credentials**: Clear error messages passed to components +3. **Token Expiration**: Automatic logout with cleanup +4. **Service Unavailable**: Graceful degradation with retry logic + +## Testing + +The dependency injection architecture makes testing straightforward: + +```typescript +// Mock the auth service for testing +const mockAuthService = { + isAuthenticated: ref(true), + currentUser: ref({ id: 'test-user', username: 'test' }), + login: vi.fn(), + logout: vi.fn() +} + +// Inject mock in tests +container.provide(SERVICE_TOKENS.AUTH_SERVICE, mockAuthService) +``` + +## Security Considerations + +1. **Token Storage**: Secure storage in localStorage with automatic cleanup +2. **API Integration**: All requests authenticated via LNBits tokens +3. **State Management**: Reactive state prevents stale authentication data +4. **Service Isolation**: Authentication logic isolated in dedicated service + +## Future Enhancements + +1. **Token Refresh**: Automatic token refresh before expiration +2. **Multi-Factor Authentication**: Support for additional auth factors +3. **Session Management**: Enhanced session handling and persistence +4. **Audit Logging**: Authentication event logging for security \ No newline at end of file diff --git a/docs/02-modules/chat-module/integration.md b/docs/02-modules/chat-module/integration.md index 753265f..bd07af6 100644 --- a/docs/02-modules/chat-module/integration.md +++ b/docs/02-modules/chat-module/integration.md @@ -24,14 +24,15 @@ A Vue component that provides the chat interface with: - Encrypted message exchange - Connection status indicators -### 2. useNostrChat.ts -**Location**: `src/composables/useNostrChat.ts` +### 2. ChatService +**Location**: `src/modules/chat/services/chat-service.ts` -A composable that handles: -- Nostr relay connections +A service-based architecture that handles: +- Nostr relay connections via dependency injection - Message encryption/decryption -- User authentication with LNBits +- User authentication through AuthService - Real-time message subscription +- Integration with modular service architecture ### 3. ChatPage.vue **Location**: `src/pages/ChatPage.vue` @@ -83,9 +84,10 @@ Response: ## Features ### 1. User Integration -- Automatically loads peers from LNBits user database -- Uses existing `pubkey` and `prvkey` fields -- Admin-only access to private keys for messaging +- Automatically loads peers from LNBits user database via dependency injection +- Uses existing `pubkey` and `prvkey` fields from AuthService +- Authentication managed through centralized AuthService +- No dual authentication issues - single source of truth ### 2. Nostr Relay Integration - Connects to multiple Nostr relays for redundancy diff --git a/docs/03-core-services/authentication.md b/docs/03-core-services/authentication.md index 71c23fd..0d99f72 100644 --- a/docs/03-core-services/authentication.md +++ b/docs/03-core-services/authentication.md @@ -78,11 +78,74 @@ The application uses the following LNBits API endpoints: - Route protection for authenticated pages - Secure logout with token cleanup -## Migration from Nostr +## Architecture -The following components have been removed or replaced: +The authentication system uses a **dependency injection pattern** for clean modular architecture: -- `useIdentity.ts` → `useAuth.ts` +### Core Components + +1. **AuthService** (`src/modules/base/auth/auth-service.ts`) + - Singleton service that manages authentication state + - Handles API calls to LNBits + - Provides reactive state management + +2. **useAuthService** (`src/composables/useAuthService.ts`) + - Wrapper composable that provides unified access to AuthService + - Uses dependency injection to access the service + - Provides consistent API for all components + +3. **Dependency Injection Container** (`src/core/di-container.ts`) + - Manages service registration and injection + - Ensures single source of truth across modules + +### Usage Pattern + +Components access authentication through the `useAuth()` composable: + +```typescript +import { useAuth } from '@/composables/useAuthService' + +export default defineComponent({ + setup() { + const auth = useAuth() + + // Access authentication state + const isAuthenticated = auth.isAuthenticated + const currentUser = auth.currentUser + + // Call authentication methods + const login = (credentials) => auth.login(credentials) + const logout = () => auth.logout() + + return { + isAuthenticated, + currentUser, + login, + logout + } + } +}) +``` + +### Service Registration + +The AuthService is registered in the base module and made available through dependency injection: + +```typescript +// In base module +container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService) + +// In components +const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE) +``` + +## Migration from Legacy Architecture + +The following components have been updated: + +- **Legacy**: Global `useAuth.ts` composable → **Current**: `useAuthService.ts` with dependency injection +- **Legacy**: Direct service imports → **Current**: Dependency injection pattern +- **Legacy**: Dual authentication detection → **Current**: Single source of truth via AuthService - `IdentityDialog.vue` → `LoginDialog.vue` - `PasswordDialog.vue` → Integrated into `LoginDialog.vue` - Nostr connection status → User authentication status