Update documentation to reflect new authentication architecture
Remove legacy references to global auth composable and document the new dependency injection pattern with single source of truth. Key Documentation Updates: • Update authentication.md with DI architecture details and usage patterns • Update chat integration docs to reference AuthService and remove legacy patterns • Add comprehensive authentication-architecture.md with full technical details • Document migration path from legacy global auth to current DI pattern Content Changes: • Replace useAuth.ts references with useAuthService.ts • Document AuthService as singleton with dependency injection • Add code examples for both component and service usage • Explain benefits of new architecture (single source of truth, no timing issues) • Update chat integration to reflect service-based architecture 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4feb5459cc
commit
6cb10a31db
3 changed files with 311 additions and 11 deletions
235
docs/01-architecture/authentication-architecture.md
Normal file
235
docs/01-architecture/authentication-architecture.md
Normal file
|
|
@ -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<User | null>(null)
|
||||||
|
public isLoading = ref(false)
|
||||||
|
public error = ref<Error | null>(null)
|
||||||
|
|
||||||
|
// Computed properties for compatibility
|
||||||
|
public currentUser = computed(() => this.user.value)
|
||||||
|
public userDisplay = computed(() => { /* user display logic */ })
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
async login(credentials: LoginCredentials): Promise<void>
|
||||||
|
async register(data: RegisterData): Promise<void>
|
||||||
|
async logout(): Promise<void>
|
||||||
|
async checkAuth(): Promise<boolean>
|
||||||
|
async updatePassword(current: string, newPass: string): Promise<void>
|
||||||
|
async updateProfile(data: Partial<User>): Promise<void>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useAuth } from '@/composables/useAuthService'
|
||||||
|
|
||||||
|
const auth = useAuth()
|
||||||
|
|
||||||
|
// Access reactive state
|
||||||
|
const isAuthenticated = auth.isAuthenticated
|
||||||
|
const currentUser = auth.currentUser
|
||||||
|
|
||||||
|
// Call methods
|
||||||
|
const handleLogin = async (credentials) => {
|
||||||
|
await auth.login(credentials)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
@ -24,14 +24,15 @@ A Vue component that provides the chat interface with:
|
||||||
- Encrypted message exchange
|
- Encrypted message exchange
|
||||||
- Connection status indicators
|
- Connection status indicators
|
||||||
|
|
||||||
### 2. useNostrChat.ts
|
### 2. ChatService
|
||||||
**Location**: `src/composables/useNostrChat.ts`
|
**Location**: `src/modules/chat/services/chat-service.ts`
|
||||||
|
|
||||||
A composable that handles:
|
A service-based architecture that handles:
|
||||||
- Nostr relay connections
|
- Nostr relay connections via dependency injection
|
||||||
- Message encryption/decryption
|
- Message encryption/decryption
|
||||||
- User authentication with LNBits
|
- User authentication through AuthService
|
||||||
- Real-time message subscription
|
- Real-time message subscription
|
||||||
|
- Integration with modular service architecture
|
||||||
|
|
||||||
### 3. ChatPage.vue
|
### 3. ChatPage.vue
|
||||||
**Location**: `src/pages/ChatPage.vue`
|
**Location**: `src/pages/ChatPage.vue`
|
||||||
|
|
@ -83,9 +84,10 @@ Response:
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### 1. User Integration
|
### 1. User Integration
|
||||||
- Automatically loads peers from LNBits user database
|
- Automatically loads peers from LNBits user database via dependency injection
|
||||||
- Uses existing `pubkey` and `prvkey` fields
|
- Uses existing `pubkey` and `prvkey` fields from AuthService
|
||||||
- Admin-only access to private keys for messaging
|
- Authentication managed through centralized AuthService
|
||||||
|
- No dual authentication issues - single source of truth
|
||||||
|
|
||||||
### 2. Nostr Relay Integration
|
### 2. Nostr Relay Integration
|
||||||
- Connects to multiple Nostr relays for redundancy
|
- Connects to multiple Nostr relays for redundancy
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,74 @@ The application uses the following LNBits API endpoints:
|
||||||
- Route protection for authenticated pages
|
- Route protection for authenticated pages
|
||||||
- Secure logout with token cleanup
|
- 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`
|
- `IdentityDialog.vue` → `LoginDialog.vue`
|
||||||
- `PasswordDialog.vue` → Integrated into `LoginDialog.vue`
|
- `PasswordDialog.vue` → Integrated into `LoginDialog.vue`
|
||||||
- Nostr connection status → User authentication status
|
- Nostr connection status → User authentication status
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue