# Phase 4: Security - Context **Gathered:** 2026-03-11 **Status:** Ready for planning ## Phase Boundary All agent-server communication is authenticated and integrity-protected. JWT for API access control, Ed25519 signatures for pushed configuration/commands, bootstrap token for initial agent registration. This phase secures the communication channel between agents and server — not user/UI auth (deferred to v2 with web UI). ## Implementation Decisions ### Bootstrap token flow - Single shared token from `CAMELEER_AUTH_TOKEN` env var — no config file fallback - Agent passes bootstrap token via `Authorization: Bearer ` header on `POST /register` - Server returns `401 Unauthorized` when token is missing or invalid — no detail about what's wrong - Server fails fast on startup if `CAMELEER_AUTH_TOKEN` is not set — prevents running insecure - Hot rotation via dual-token overlap: support `CAMELEER_AUTH_TOKEN_PREVIOUS` env var, server accepts both during rotation window. Remove old var when all agents updated ### JWT lifecycle - Access JWT expires after 1 hour - Separate refresh token with 7-day expiry, issued alongside access JWT at registration - Agent calls `POST /api/v1/agents/{id}/refresh` with refresh token to get new access JWT - JWT claims: `sub` = agentId, custom claim for group - Registration response includes both access JWT and refresh token (replaces current `serverPublicKey: null` placeholder with actual public key) ### Ed25519 signing - Ephemeral keypair generated fresh each server startup — no persistence needed - Agents receive public key during registration; must re-register after server restart to get new key - Signature included as a `signature` field in the SSE event data JSON — agent verifies payload minus signature field - All command types signed (config-update, deep-trace, replay) — uniform security model ### Endpoint protection - Public (no JWT): `GET /health`, `POST /register` (uses bootstrap token), OpenAPI/Swagger UI docs - Protected (JWT required): all other endpoints including ingestion (`/data/**`), search, agent management, commands - SSE connections authenticated via JWT as query parameter: `/agents/{id}/events?token=` (EventSource API doesn't support custom headers) - Spring Security filter chain (`spring-boot-starter-security`) with custom `JwtAuthenticationFilter` ### Claude's Discretion - JWT signing algorithm (HMAC with server secret vs Ed25519 for JWT too) - Nimbus JOSE+JWT vs jjwt vs other JWT library - Ed25519 implementation library (Bouncy Castle vs JDK built-in) - Spring Security configuration details (SecurityFilterChain bean, permit patterns) - Refresh token storage mechanism (in-memory map, agent registry, or stateless) ## Specific Ideas - "This phase and version really is about securing the communication channel between agent and server" — scope is agent-server auth, not user-facing auth - Bootstrap token rotation without downtime was explicitly called out as important - Agents already re-register on restart (Phase 3 design), so ephemeral Ed25519 keys align naturally ## Existing Code Insights ### Reusable Assets - `ProtocolVersionInterceptor` + `WebConfig`: Path-based request filtering pattern — Spring Security filter chain replaces this for auth - `AgentRegistrationController.register()`: Already returns `serverPublicKey: null` — fill with real Ed25519 public key - `SseConnectionManager.sendEvent()`: SSE delivery point — signing hooks into data before this call - `AgentRegistryConfig`: Configuration properties pattern — extend for security settings (token expiry, etc.) - `AgentRegistryService`: Agent lookup by ID — used for JWT validation (verify agent exists) ### Established Patterns - Core module: interfaces + domain logic; App module: Spring Boot + implementations - `application.yml` for all configurable values with sensible defaults - `AgentEventListener` interface decouples core from app module — signing logic can live in app module ### Integration Points - `POST /register` needs bootstrap token validation before reaching current registration logic - `SseConnectionManager.connect()` needs JWT validation from query parameter - `SseConnectionManager.onCommandReady()` needs to sign payload before delivery - All existing controllers need JWT auth enforced — Spring Security filter handles this transparently - `WebConfig` excluded paths need to align with Spring Security permit patterns ## Deferred Ideas - User/UI authentication — belongs with web UI in v2 - Role-based access control (admin vs agent vs viewer) — future phase - Token revocation list — evaluate after v1 usage patterns - Mutual TLS as additional transport security — infrastructure concern, not application layer - Key rotation API endpoint — adds attack surface, stick with restart-based rotation for v1 --- *Phase: 04-security* *Context gathered: 2026-03-11*