initial commit
This commit is contained in:
214
interfaces/websocket/server/docs/authentication.md
Normal file
214
interfaces/websocket/server/docs/authentication.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# 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
|
Reference in New Issue
Block a user