Files
paperclip/doc/plans/agent-authentication-implementation.md
Forgotten fe6a8687c1 Implement local agent JWT authentication for adapters
Add HS256 JWT-based authentication for local adapters (claude_local, codex_local)
so agents authenticate automatically without manual API key configuration. The
server mints short-lived JWTs per heartbeat run and injects them as PAPERCLIP_API_KEY.
The auth middleware verifies JWTs alongside existing static API keys.

Includes: CLI onboard/doctor JWT secret management, env command for deployment,
config path resolution from ancestor directories, dotenv loading on server startup,
event payload secret redaction, multi-status issue filtering, and adapter transcript
parsing for thinking/user message kinds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 16:46:45 -06:00

73 lines
2.7 KiB
Markdown

# Agent Authentication — P0 Local Adapter JWT Implementation
## Scope
- In-scope adapters: `claude_local`, `codex_local`.
- Goal: zero-configuration auth for local adapters while preserving static keys for all other call paths.
- Out-of-scope for P0: rotation UX, per-device revocation list, and CLI onboarding.
## 1) Token format and config
- Use HS256 JWTs with claims:
- `sub` (agent id)
- `company_id`
- `adapter_type`
- `run_id`
- `iat`
- `exp`
- optional `jti` (run token id)
- New config/env settings:
- `PAPERCLIP_AGENT_JWT_SECRET`
- `PAPERCLIP_AGENT_JWT_TTL_SECONDS` (default: `172800`)
- `PAPERCLIP_AGENT_JWT_ISSUER` (default: `paperclip`)
- `PAPERCLIP_AGENT_JWT_AUDIENCE` (default: `paperclip-api`)
## 2) Dual authentication path in `actorMiddleware`
1. Keep the existing DB key lookup path unchanged (`agent_api_keys` hash lookup).
2. If no DB key matches, add JWT verification in `server/src/middleware/auth.ts`.
3. On JWT success:
- set `req.actor = { type: "agent", agentId, companyId }`.
- optionally guard against terminated agents.
4. Continue board fallback for requests without valid authentication.
## 3) Opt-in adapter capability
1. Extend `ServerAdapterModule` (likely `packages/adapter-utils/src/types.ts`) with a capability flag:
- `supportsLocalAgentJwt?: true`.
2. Enable it on:
- `server/src/adapters/registry.ts` for `claude_local` and `codex_local`.
3. Keep `process`/`http` adapters unset for P0.
4. In `server/src/services/heartbeat.ts`, when adapter supports JWT:
- mint JWT per heartbeat run before execute.
- include token in adapter execution context.
## 4) Local env injection behavior
1. In:
- `packages/adapters/claude-local/src/server/execute.ts`
- `packages/adapters/codex-local/src/server/execute.ts`
inject `PAPERCLIP_API_KEY` from context token.
- Preserve existing behavior for explicit user-defined env vars in `adapterConfig.env`:
- if user already sets `PAPERCLIP_API_KEY`, do not overwrite it.
- Continue injecting:
- `PAPERCLIP_AGENT_ID`
- `PAPERCLIP_COMPANY_ID`
- `PAPERCLIP_API_URL`
## 5) Documentation updates
- Update operator-facing docs to remove manual key setup expectation for local adapters:
- `skills/paperclip/SKILL.md`
- `cli/src/commands/heartbeat-run.ts` output/help examples if they mention manual API key setup.
## 6) P0 acceptance criteria
- Local adapters authenticate without manual `PAPERCLIP_API_KEY` config.
- Existing static keys (`agent_api_keys`) still work unchanged.
- Auth remains company-scoped (`req.actor.companyId` used by existing checks).
- JWT generation and verification errors are logged as non-leaking structured events.
- Scope remains local-only (`claude_local`, `codex_local`) while adapter capability model is generic.