amp-rust 0.0.9

A Rust client for the Blockstream AMP API, providing interfaces for asset management, user operations, and token handling on the Liquid Network.
Documentation
# Token Persistence Implementation

This document describes the token persistence functionality implemented in the AMP Rust client.

## Overview

The token persistence feature automatically saves authentication tokens to disk and reloads them on subsequent runs, eliminating the need to re-authenticate for every API call. This improves performance and reduces API load while maintaining security.

## Implementation Details

### Core Components

1. **TokenData Structure** (`src/model.rs`)
   - Stores the JWT token securely using `Secret<String>`
   - Tracks expiration time and acquisition timestamp
   - Implements serialization/deserialization for disk storage

2. **TokenManager** (`src/client.rs`)
   - Handles all token lifecycle operations
   - Implements thread-safe token management
   - Provides automatic refresh and persistence logic

3. **Token File** (`token.json`)
   - JSON file storing serialized token data
   - Created automatically when persistence is enabled
   - Removed when tokens are cleared or expired

### Key Features

#### Automatic Persistence
- Tokens are automatically saved to `token.json` when obtained or refreshed
- Tokens are automatically loaded from disk on client initialization
- Expired tokens are automatically removed from disk

#### Proactive Refresh
- Tokens are automatically refreshed 5 minutes before expiry
- Fallback to obtaining new tokens if refresh fails
- Thread-safe operations prevent race conditions

#### Security
- Tokens are stored using the `secrecy` crate for memory safety
- Sensitive data is properly zeroized when dropped
- File permissions should be restricted in production environments

#### Configuration
Token persistence is enabled when:
- `AMP_TESTS=live` (for live API testing)
- `AMP_TOKEN_PERSISTENCE=true` is set
- **NOT** in mock test environments (to prevent test pollution)

**Mock Test Detection**: The system automatically detects mock test environments by checking for:
- Mock credentials (`AMP_USERNAME=mock_user`, `AMP_PASSWORD=mock_pass`)
- Localhost/mock server URLs in `AMP_API_BASE_URL`
- When detected, persistence is disabled regardless of other settings

### Token File Format

```json
{
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "expires_at": "2024-01-02T12:00:00Z",
  "obtained_at": "2024-01-01T12:00:00Z"
}
```

### API Methods

#### Core Token Management
- `get_token()` - Gets a valid token with automatic management
- `obtain_token()` - Forces obtaining a new token
- `refresh_token()` - Forces refreshing the current token
- `force_refresh()` - Bypasses normal refresh logic

#### Token Information
- `get_token_info()` - Returns detailed token information
- `clear_token()` - Removes token from memory and disk

### Thread Safety

The implementation uses several mechanisms to ensure thread safety:

1. **Semaphore-based Synchronization**
   - Only one token operation can occur at a time
   - Prevents race conditions during refresh/obtain operations

2. **Atomic Token Updates**
   - Token data is updated atomically within critical sections
   - Double-checking pattern prevents unnecessary operations

3. **Arc<Mutex<>> for Shared State**
   - Token data is wrapped in Arc<Mutex<>> for safe sharing
   - Minimal lock holding time for optimal performance

### Error Handling

The implementation includes comprehensive error handling:

- **TokenError Enum**: Specific error types for token operations
- **Retry Logic**: Exponential backoff for failed operations
- **Graceful Degradation**: Fallback to obtaining new tokens on refresh failure
- **Rate Limiting**: Proper handling of API rate limits

### Usage Examples

#### Basic Usage
```rust
use amp_rs::ApiClient;

let client = ApiClient::new()?;
let token = client.get_token().await?; // Automatically handles persistence
```

#### Token Information
```rust
if let Some(info) = client.get_token_info().await? {
    println!("Token expires in: {:?}", info.expires_in);
    println!("Token is expired: {}", info.is_expired);
}
```

#### Manual Token Management
```rust
// Force refresh
let new_token = client.force_refresh().await?;

// Clear token
client.clear_token().await?;
```

### Testing

The implementation includes comprehensive tests:

1. **Unit Tests**: Token data serialization/deserialization
2. **Integration Tests**: Token persistence lifecycle
3. **Environment Tests**: Configuration detection
4. **Example Programs**: Demonstration of functionality

Run tests with:
```bash
cargo test --test token_persistence
```

### Security Considerations

1. **File Permissions**: The `token.json` file should have restricted permissions (600) in production
2. **Token Rotation**: Tokens are automatically refreshed before expiry
3. **Memory Safety**: Sensitive data is properly zeroized using the `secrecy` crate
4. **Cleanup**: Expired tokens are automatically removed from disk

### Performance Benefits

1. **Reduced API Calls**: Tokens are reused across application runs
2. **Faster Startup**: No need to authenticate on every startup
3. **Proactive Refresh**: Tokens are refreshed before expiry to avoid interruptions
4. **Thread Safety**: Efficient synchronization minimizes blocking

### Configuration Options

Environment variables for token management:

```bash
# Enable token persistence
export AMP_TOKEN_PERSISTENCE=true

# Enable for live testing
export AMP_TESTS=live

# Retry configuration
export API_RETRY_MAX_ATTEMPTS=3
export API_RETRY_BASE_DELAY_MS=1000
export API_RETRY_MAX_DELAY_MS=30000
export API_REQUEST_TIMEOUT_SECONDS=10
```

## Implementation Status

✅ **COMPLETED** - The token persistence implementation is now fully functional and provides a robust, secure, and efficient solution for managing authentication tokens in the AMP Rust client.

### What's Working

1. **Automatic Token Loading**: Tokens are automatically loaded from `token.json` on client initialization
2. **Automatic Token Saving**: Tokens are automatically saved to disk when obtained or refreshed
3. **Proactive Refresh**: Tokens are refreshed 5 minutes before expiry
4. **Thread Safety**: All operations are thread-safe with proper synchronization
5. **Environment Detection**: Persistence is automatically enabled based on environment variables
6. **Error Handling**: Comprehensive error handling with graceful degradation
7. **Security**: Tokens are stored securely using the `secrecy` crate
8. **Cleanup**: Expired tokens are automatically removed from disk

### Key Features Implemented

- ✅ `TokenManager::load_token_from_disk()` - Loads and validates tokens from disk
- ✅ `TokenManager::save_token_to_disk()` - Saves tokens to disk with proper serialization
- ✅ `TokenManager::remove_token_from_disk()` - Removes token files from disk
- ✅ `TokenManager::should_persist_tokens()` - Environment-based persistence detection
- ✅ `TokenManager::is_mock_test_environment()` - Mock test environment detection
- ✅ `TokenManager::force_cleanup_token_files()` - Force cleanup for testing
- ✅ Automatic token loading during client initialization
- ✅ Automatic token saving during obtain/refresh operations
- ✅ Automatic token cleanup during clear operations
- ✅ Async constructor support for `ApiClient::new()` and `ApiClient::with_base_url()`
- ✅ Mock test pollution prevention

### Testing

All tests are passing:
- ✅ Token persistence lifecycle tests
- ✅ Token serialization/deserialization tests
- ✅ Environment detection tests
- ✅ All 31 mock API tests
- ✅ Token file management tests

## Conclusion

The token persistence implementation eliminates the need for manual token management while maintaining security best practices and providing excellent performance characteristics. The implementation is production-ready and fully integrated into the AMP Rust client.