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

6.4 KiB

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:

{
  "nonce": "nonce_1234567890_abcdef",
  "expires_at": 1234567890
}

Health Check

GET /auth/health

Response:

{
  "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)

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

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

// 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

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