Update modular design documentation and workspace configuration
- Change the active file in workspace.json to point to the new modular-design.md. - Revise modular-design.md to enhance clarity and structure, including a new table of contents and updated sections on design philosophy, architecture components, and service abstractions. - Remove outdated content and improve the overall presentation of modular design patterns and best practices. These updates aim to streamline the documentation for better accessibility and understanding of the modular architecture.
This commit is contained in:
parent
670a42dd9b
commit
a373fa714d
5 changed files with 620 additions and 515 deletions
|
|
@ -1,172 +1,261 @@
|
|||
# Authentication System
|
||||
# 🔐 Authentication Service
|
||||
|
||||
This web application now uses LNBits username/password authentication instead of Nostr keypairs.
|
||||
> **User identity and session management** with Nostr key handling, dependency injection architecture, and secure client-side key management.
|
||||
|
||||
## Overview
|
||||
## Table of Contents
|
||||
|
||||
The authentication system has been completely replaced with a traditional username/password system that integrates with LNBits. Users can now:
|
||||
- [[#Service Overview]]
|
||||
- [[#Architecture]]
|
||||
- [[#Key Features]]
|
||||
- [[#Usage Patterns]]
|
||||
- [[#Authentication Flow]]
|
||||
- [[#Security Considerations]]
|
||||
|
||||
- Register new accounts with username and password
|
||||
- Login with username/email and password
|
||||
- Manage their profile information
|
||||
- Logout securely
|
||||
## Service Overview
|
||||
|
||||
## Configuration
|
||||
The `AuthService` is a core infrastructure service that manages user authentication, identity, and session state throughout the application. It provides secure Nostr key management with client-side encryption and reactive state management.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Create a `.env` file in the `web-app` directory with the following variables:
|
||||
|
||||
```env
|
||||
# LNBits Base URL Configuration
|
||||
# Set this to your LNBits instance base URL
|
||||
# Example: http://localhost:5000 or https://your-lnbits-instance.com
|
||||
VITE_LNBITS_BASE_URL=http://localhost:5000
|
||||
|
||||
# Enable debug logging for LNBits API calls
|
||||
VITE_LNBITS_DEBUG=false
|
||||
|
||||
# App Configuration
|
||||
VITE_APP_TITLE=Ario
|
||||
VITE_APP_DESCRIPTION=Your secure platform for events and community management
|
||||
```
|
||||
|
||||
### LNBits Setup
|
||||
|
||||
1. Ensure your LNBits instance is running and accessible
|
||||
2. Make sure the username/password authentication method is enabled in LNBits
|
||||
3. Configure CORS if your LNBits instance is on a different domain
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The application uses the following LNBits API endpoints:
|
||||
|
||||
- `POST /api/v1/auth` - Login
|
||||
- `POST /api/v1/auth/register` - Register new user
|
||||
- `POST /api/v1/auth/logout` - Logout
|
||||
- `GET /api/v1/auth` - Get current user
|
||||
- `PUT /api/v1/auth/password` - Update password
|
||||
- `PUT /api/v1/auth/update` - Update profile
|
||||
|
||||
## Components
|
||||
|
||||
### New Components
|
||||
|
||||
- `LoginDialog.vue` - Modal dialog for login/register
|
||||
- `UserProfile.vue` - Display user information and logout
|
||||
- `Login.vue` - Full-page login/register form
|
||||
|
||||
### Updated Components
|
||||
|
||||
- `App.vue` - Now uses new authentication system
|
||||
- `Navbar.vue` - Shows user status and logout option
|
||||
- `Home.vue` - Displays welcome message and user profile
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
1. **App Initialization**: The app checks for existing authentication token on startup
|
||||
2. **Route Protection**: Routes with `requiresAuth: true` redirect to login if not authenticated
|
||||
3. **Login/Register**: Users can create accounts or login with existing credentials
|
||||
4. **Token Management**: Access tokens are stored in localStorage and automatically included in API requests
|
||||
5. **Logout**: Clears tokens and redirects to login page
|
||||
|
||||
## Security Features
|
||||
|
||||
- JWT tokens for session management
|
||||
- Secure password handling (handled by LNBits)
|
||||
- Automatic token refresh
|
||||
- Route protection for authenticated pages
|
||||
- Secure logout with token cleanup
|
||||
**Service Token**: `SERVICE_TOKENS.AUTH_SERVICE`
|
||||
**Location**: `src/modules/base/auth/auth-service.ts`
|
||||
**Dependencies**: `LnbitsAPI` for backend integration
|
||||
|
||||
## Architecture
|
||||
|
||||
The authentication system uses a **dependency injection pattern** for clean modular architecture:
|
||||
|
||||
### 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:
|
||||
### Dependency Injection Pattern
|
||||
The authentication system uses dependency injection for clean, modular access:
|
||||
|
||||
```typescript
|
||||
// Service registration (base module)
|
||||
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService)
|
||||
|
||||
// Service consumption (components)
|
||||
const auth = useAuth() // Via composable wrapper
|
||||
|
||||
// Service consumption (other services)
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
```
|
||||
|
||||
### Reactive State Management
|
||||
AuthService integrates Vue's reactivity system for automatic UI updates:
|
||||
|
||||
```typescript
|
||||
export class AuthService extends BaseService {
|
||||
public isAuthenticated = ref(false)
|
||||
public user = ref<User | null>(null)
|
||||
public isLoading = ref(false)
|
||||
public error = ref<Error | null>(null)
|
||||
|
||||
// Computed properties for component compatibility
|
||||
public currentUser = computed(() => this.user.value)
|
||||
public userDisplay = computed(() => this.user.value?.name || 'Anonymous')
|
||||
}
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### 🔑 **Nostr Key Management**
|
||||
- **Secure Key Generation** - Client-side key pair creation with proper entropy
|
||||
- **Key Import/Export** - Support for existing Nostr keys (nsec/hex formats)
|
||||
- **Encrypted Storage** - User keys encrypted with password-derived encryption
|
||||
- **Key Recovery** - Secure key backup and restoration mechanisms
|
||||
|
||||
### 👤 **User Identity & Profiles**
|
||||
- **Nostr Profile Management** - NIP-01 compatible user metadata
|
||||
- **Profile Updates** - Real-time profile information synchronization
|
||||
- **Display Name Handling** - Fallback from name → display_name → truncated pubkey
|
||||
- **Avatar Support** - Profile picture URLs with fallback handling
|
||||
|
||||
### 🔒 **Session Management**
|
||||
- **Persistent Sessions** - Secure localStorage-based session persistence
|
||||
- **Auto-Initialization** - Automatic session restoration on app startup
|
||||
- **Secure Logout** - Complete session cleanup and key removal
|
||||
- **Token Management** - LNBits API token handling and refresh
|
||||
|
||||
### 🌐 **Backend Integration**
|
||||
- **LNBits API** - Wallet integration for Lightning functionality
|
||||
- **Event Publishing** - User profile publishing to Nostr relays
|
||||
- **Real-time Updates** - Reactive profile updates across relays
|
||||
|
||||
## Usage Patterns
|
||||
|
||||
### Component Usage (Recommended)
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
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
|
||||
const auth = useAuth()
|
||||
|
||||
// Access reactive authentication state
|
||||
const isAuthenticated = auth.isAuthenticated
|
||||
const currentUser = auth.currentUser
|
||||
const userDisplay = auth.userDisplay
|
||||
|
||||
// Authentication methods
|
||||
const handleLogin = async (privateKey: string) => {
|
||||
try {
|
||||
await auth.login({ privateKey })
|
||||
// Success handled automatically by service
|
||||
} catch (error) {
|
||||
// Error handling
|
||||
console.error('Login failed:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleLogout = () => auth.logout()
|
||||
</script>
|
||||
```
|
||||
|
||||
### Service Usage (Other Services)
|
||||
```typescript
|
||||
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
|
||||
|
||||
export class ChatService extends BaseService {
|
||||
private get authService(): AuthService {
|
||||
return this.dependencies.get('AuthService') as AuthService
|
||||
}
|
||||
|
||||
async sendMessage(content: string) {
|
||||
const user = this.authService.user.value
|
||||
if (!user?.pubkey || !user?.prvkey) {
|
||||
throw new Error('Authentication required')
|
||||
}
|
||||
|
||||
// Use authenticated user data for message signing
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Store Integration
|
||||
```typescript
|
||||
// In Pinia stores
|
||||
export const useMyStore = defineStore('myStore', () => {
|
||||
const auth = useAuth()
|
||||
|
||||
// Reactive dependency on auth state
|
||||
const userSpecificData = computed(() => {
|
||||
if (!auth.isAuthenticated.value) return []
|
||||
return loadDataForUser(auth.currentUser.value.pubkey)
|
||||
})
|
||||
|
||||
return { userSpecificData }
|
||||
})
|
||||
```
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### 1. App Initialization
|
||||
```typescript
|
||||
// App startup sequence
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
await authService.initialize()
|
||||
|
||||
if (authService.isAuthenticated.value) {
|
||||
// User has valid session - proceed to app
|
||||
} else {
|
||||
// Redirect to login/onboarding
|
||||
}
|
||||
```
|
||||
|
||||
### 2. User Login Process
|
||||
1. **Key Input** - User provides private key (nsec, hex, or generates new)
|
||||
2. **Key Validation** - Validate key format and derive public key
|
||||
3. **Profile Loading** - Fetch existing Nostr profile if available
|
||||
4. **Session Creation** - Encrypt and store keys securely
|
||||
5. **Service Initialization** - Initialize user-scoped services
|
||||
6. **UI Updates** - Reactive state triggers navigation/UI changes
|
||||
|
||||
### 3. Authentication Guards
|
||||
```typescript
|
||||
// Router guards use auth service
|
||||
router.beforeEach((to, from, next) => {
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
|
||||
if (to.meta.requiresAuth && !authService.isAuthenticated.value) {
|
||||
next('/login')
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Service Registration
|
||||
### 4. Logout Process
|
||||
1. **Session Cleanup** - Clear encrypted keys from storage
|
||||
2. **Service Reset** - Reset all user-scoped service state
|
||||
3. **Relay Cleanup** - Close user-specific Nostr subscriptions
|
||||
4. **UI Reset** - Clear user data from stores and components
|
||||
5. **Navigation** - Redirect to login/public areas
|
||||
|
||||
The AuthService is registered in the base module and made available through dependency injection:
|
||||
## Security Considerations
|
||||
|
||||
### 🔐 **Client-Side Security**
|
||||
- **No Server Keys** - Private keys never leave the client
|
||||
- **Encrypted Storage** - Keys encrypted with user-provided password
|
||||
- **Memory Management** - Secure key handling in memory
|
||||
- **Input Validation** - Strict validation of key formats and data
|
||||
|
||||
### 🌐 **Network Security**
|
||||
- **HTTPS Only** - All API calls over encrypted connections
|
||||
- **Token Security** - LNBits tokens with appropriate scoping
|
||||
- **Request Validation** - API request signature verification
|
||||
- **Error Handling** - No sensitive data in error messages
|
||||
|
||||
### 🛡️ **Data Protection**
|
||||
- **User-Scoped Storage** - Data isolation between users
|
||||
- **Automatic Cleanup** - Session data cleared on logout
|
||||
- **Profile Privacy** - Configurable profile information sharing
|
||||
- **Key Rotation** - Support for updating authentication credentials
|
||||
|
||||
## API Reference
|
||||
|
||||
### AuthService Methods
|
||||
```typescript
|
||||
// In base module
|
||||
container.provide(SERVICE_TOKENS.AUTH_SERVICE, authService)
|
||||
|
||||
// In components
|
||||
const authService = injectService(SERVICE_TOKENS.AUTH_SERVICE)
|
||||
interface AuthService {
|
||||
// Core authentication
|
||||
login(credentials: LoginCredentials): Promise<void>
|
||||
logout(): Promise<void>
|
||||
initialize(): Promise<void>
|
||||
|
||||
// Key management
|
||||
generateKeyPair(): Promise<{ pubkey: string, prvkey: string }>
|
||||
importPrivateKey(key: string): Promise<void>
|
||||
exportPrivateKey(): string | null
|
||||
|
||||
// Profile management
|
||||
updateProfile(profile: UserMetadata): Promise<void>
|
||||
publishProfile(): Promise<void>
|
||||
|
||||
// Reactive state (readonly)
|
||||
readonly isAuthenticated: ComputedRef<boolean>
|
||||
readonly currentUser: ComputedRef<User | null>
|
||||
readonly userDisplay: ComputedRef<UserDisplay>
|
||||
readonly isLoading: Ref<boolean>
|
||||
readonly error: Ref<Error | null>
|
||||
}
|
||||
```
|
||||
|
||||
## Migration from Legacy Architecture
|
||||
### LoginCredentials Interface
|
||||
```typescript
|
||||
interface LoginCredentials {
|
||||
privateKey?: string // Existing key (nsec or hex)
|
||||
generateNew?: boolean // Generate new key pair
|
||||
password?: string // For key encryption
|
||||
profile?: UserMetadata // Initial profile data
|
||||
}
|
||||
```
|
||||
|
||||
The following components have been updated:
|
||||
## See Also
|
||||
|
||||
- **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
|
||||
### Architecture Documentation
|
||||
- **[[../01-architecture/authentication-architecture|🔐 Authentication Architecture]]** - Detailed architecture overview
|
||||
- **[[../01-architecture/dependency-injection|⚙️ Dependency Injection]]** - Service container patterns
|
||||
- **[[index|⚙️ Core Services Overview]]** - Related infrastructure services
|
||||
|
||||
## Development
|
||||
### Module Documentation
|
||||
- **[[../02-modules/base-module/index|🏗️ Base Module]]** - Authentication service registration
|
||||
- **[[../04-development/security|🛡️ Security Guidelines]]** - Security best practices
|
||||
|
||||
To run the application with the new authentication system:
|
||||
---
|
||||
|
||||
1. Set up your LNBits instance
|
||||
2. Configure the environment variables
|
||||
3. Run the development server: `npm run dev`
|
||||
4. Access the application and test login/register functionality
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **CORS Errors**: Ensure your LNBits instance allows requests from your frontend domain
|
||||
2. **Authentication Failures**: Check that username/password auth is enabled in LNBits
|
||||
3. **API Connection**: Verify the `VITE_LNBITS_BASE_URL` is correct and points to your LNBits instance (without /api/v1)
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging by setting `VITE_LNBITS_DEBUG=true` to see detailed API request/response information in the browser console.
|
||||
**Tags:** #authentication #security #services #nostr #dependency-injection
|
||||
**Last Updated:** 2025-09-07
|
||||
**Author:** Development Team
|
||||
Loading…
Add table
Add a link
Reference in a new issue