hero/interfaces/websocket/server/docs/authentication.md
2025-07-29 01:15:23 +02:00

214 lines
6.4 KiB
Markdown

# WebSocket Server Authentication
This document describes the optional authentication features added to the Circle WebSocket server.
## Overview
The WebSocket server now supports optional secp256k1 signature-based authentication while maintaining full backward compatibility with existing clients. Authentication is completely opt-in and can be enabled per server instance.
## Features
### 1. Optional Authentication
- **Backward Compatible**: Existing clients continue to work without any changes
- **Opt-in**: Authentication can be enabled/disabled per server instance
- **Graceful Degradation**: Servers can accept both authenticated and unauthenticated connections
### 2. Nonce-based Security
- **Nonce Endpoints**: REST API for requesting cryptographic nonces
- **Replay Protection**: Each nonce can only be used once
- **Expiration**: Nonces expire after 5 minutes
- **Health Monitoring**: Health endpoint for monitoring nonce service
### 3. Signature Verification
- **secp256k1**: Uses the same cryptographic standard as Ethereum
- **Ethereum-style Signing**: Compatible with eth_sign message format
- **Public Key Recovery**: Verifies signatures against provided public keys
## API Endpoints
These HTTP API endpoints are served by the WebSocket server instance itself, on the same host and port where the WebSocket service is running.
### Nonce Request
```
GET /auth/nonce?public_key=<optional_public_key>
```
**Response:**
```json
{
"nonce": "nonce_1234567890_abcdef",
"expires_at": 1234567890
}
```
### Health Check
```
GET /auth/health
```
**Response:**
```json
{
"status": "healthy",
"active_nonces": 42,
"timestamp": 1234567890
}
```
## WebSocket Authentication
### Query Parameters
Clients can authenticate by including these query parameters in the WebSocket URL:
- `pubkey`: The client's public key in hex format (130 characters, uncompressed)
- `sig`: The signature of the nonce in hex format (130 characters)
- `nonce`: The nonce that was signed (optional)
**Example:**
```
ws://localhost:8080/{circle_pk}?pubkey=04abc123...&sig=def456...&nonce=nonce_123_abc
```
### Authentication Flow
1. **Request Nonce**: Client requests a nonce from `/auth/nonce`
2. **Sign Nonce**: Client signs the nonce with their private key
3. **Connect**: Client connects to WebSocket with `pubkey` and `sig` parameters
4. **Verify**: Server verifies the signature and accepts/rejects the connection
## Server Configuration
### Basic Server (No Authentication)
```rust
use circle_ws_lib::{ServerConfig, spawn_circle_server};
let config = ServerConfig::new(
"localhost".to_string(),
8080,
"redis://localhost".to_string(),
);
let (server_task, server_handle) = spawn_circle_server(config)?;
```
### Server with Authentication
```rust
use circle_ws_lib::{ServerConfig, spawn_circle_server};
let config = ServerConfig::new(
"localhost".to_string(),
8080,
"redis://localhost".to_string(),
).with_auth();
let (server_task, server_handle) = spawn_circle_server(config)?;
```
## Client Integration
### JavaScript/TypeScript Example
```javascript
// 1. Request nonce (from the WebSocket server's HTTP interface)
const nonceResponse = await fetch('http://localhost:8080/auth/nonce');
const { nonce } = await nonceResponse.json();
// 2. Sign nonce (using your preferred secp256k1 library)
const signature = signMessage(privateKey, nonce);
const publicKey = derivePublicKey(privateKey);
// 3. Connect with authentication (replace {circle_pk} with actual circle public key)
const ws = new WebSocket(
`ws://localhost:8080/${circle_pk}?pubkey=${publicKey}&sig=${signature}&nonce=${nonce}`
);
```
### Rust Client Example
```rust
use circle_ws_lib::auth::*;
// Request nonce. NonceClient will derive the HTTP API path from this WebSocket URL.
let nonce_client = NonceClient::from_ws_url("ws://localhost:8080/{circle_pk}")?;
let nonce_response = nonce_client.request_nonce(Some(public_key)).await?;
// Sign nonce
let signature = sign_message(&private_key, &nonce_response.nonce)?;
// Connect with authentication (replace {circle_pk} with actual circle public key)
let ws_url = format!(
"ws://localhost:8080/{}?pubkey={}&sig={}",
circle_pk, public_key, signature
);
```
## Security Considerations
### Nonce Management
- Nonces expire after 5 minutes
- Each nonce can only be used once
- Nonces are stored in memory (consider Redis for production)
### Signature Security
- Uses secp256k1 elliptic curve cryptography
- Ethereum-style message signing for compatibility
- Public key verification prevents impersonation
### Backward Compatibility
- Unauthenticated connections are allowed by default
- No breaking changes to existing APIs
- Optional authentication can be enabled gradually
## Error Handling
### Authentication Errors
- **401 Unauthorized**: Authentication required but not provided
- **403 Forbidden**: Authentication provided but invalid
- **400 Bad Request**: Malformed authentication parameters
### Nonce Errors
- **404 Not Found**: Nonce endpoint not available
- **410 Gone**: Nonce expired or already used
- **429 Too Many Requests**: Rate limiting (if implemented)
## Monitoring
### Metrics
- Active nonce count via `/auth/health`
- Authentication success/failure rates in logs
- Connection counts by authentication status
### Logging
```
INFO Incoming WebSocket connection for circle: 04abc123... (auth_enabled: true)
INFO Authentication successful for pubkey: 04abc123...
WARN Authentication failed: invalid signature
```
## Production Considerations
### Scalability
- Consider Redis-backed nonce storage for multiple server instances
- Implement rate limiting for nonce requests
- Monitor memory usage of in-memory nonce storage
### Security
- Use HTTPS/WSS in production
- Implement proper key management
- Consider certificate-based authentication for additional security
### Monitoring
- Set up alerts for authentication failure rates
- Monitor nonce service health
- Track connection patterns and anomalies
## Migration Guide
### Existing Deployments
1. **No Changes Required**: Existing clients continue to work
2. **Gradual Rollout**: Enable authentication on new servers first
3. **Client Updates**: Update clients to support authentication when ready
4. **Full Migration**: Eventually require authentication on all servers
### Testing
1. Test unauthenticated connections still work
2. Test authenticated connections with valid signatures
3. Test authentication failures are handled gracefully
4. Test nonce expiration and replay protection