# Agent Name: Agent 05 - API Keys And Access Control Stage: API Keys And Access Control Date: 2026-04-14 ## Scope Implemented the API key lifecycle and access-control stage on top of the existing authenticated admin workspace and the project or tag model from Agent 04. Completed in this stage: - added a dedicated `internal/apikeys` service for secure API key generation, SHA-256 hashing, lookup, lifecycle checks, and project scope evaluation; - implemented full API key repository support for create, update, list, revoke or activate, last-used tracking, project and tag rule storage, and effective access queries; - added minimal protected admin pages for API key list, creation, detail, update, and revoke or activate actions; - implemented one-time raw key reveal behavior by showing the generated key only in the immediate creation response while persisting only the short prefix and hash; - added permission and project-scope middleware helpers for future `/api/v1` client routes using bearer authentication; - added integration and unit coverage for hashed storage, expired or revoked key rejection, all five scope modes, scope transitions, middleware enforcement, and admin key management flow. ## Files Changed - `/Users/delete/projects/update_server/internal/app/app.go` - `/Users/delete/projects/update_server/internal/db/models.go` - `/Users/delete/projects/update_server/internal/db/apikeys.go` - `/Users/delete/projects/update_server/internal/apikeys/context.go` - `/Users/delete/projects/update_server/internal/apikeys/service.go` - `/Users/delete/projects/update_server/internal/apikeys/service_test.go` - `/Users/delete/projects/update_server/internal/http/router.go` - `/Users/delete/projects/update_server/internal/http/handlers.go` - `/Users/delete/projects/update_server/internal/http/view_data.go` - `/Users/delete/projects/update_server/internal/http/admin_api_keys.go` - `/Users/delete/projects/update_server/internal/http/api_key_middleware.go` - `/Users/delete/projects/update_server/internal/http/api_key_middleware_test.go` - `/Users/delete/projects/update_server/internal/http/api_keys_integration_test.go` - `/Users/delete/projects/update_server/internal/http/auth_integration_test.go` - `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml` - `/Users/delete/projects/update_server/web/templates/pages/api_keys.gohtml` - `/Users/delete/projects/update_server/web/templates/pages/api_key_form.gohtml` - `/Users/delete/projects/update_server/web/static/app.css` - `/Users/delete/projects/update_server/docs/agents/handoffs/05-api-keys.md` ## Database Changes - no new migrations were required because the existing `api_keys`, `api_key_project_access`, and `api_key_tag_access` tables already existed from Agent 02 and the scope guard triggers already existed from migration `0003_api_key_scope_guards.sql`; - the new repository code now actively uses those tables and trigger rules for key lifecycle, project allow or deny lists, and tag allow or deny lists; - API keys are stored with a short visible `key_prefix` and a hashed `key_hash`; the raw key is never persisted. ## API Or Route Changes - added protected admin routes: - `GET /admin/api-keys` - `GET /admin/api-keys/new` - `POST /admin/api-keys` - `GET /admin/api-keys/{apiKeyID}` - `POST /admin/api-keys/{apiKeyID}` - `POST /admin/api-keys/{apiKeyID}/activate` - added reusable middleware helpers for future client API routes: - `requireAPIKey` - `requireAPIKeyPermission` - `requireAPIKeyProjectAccess` - kept `/api/v1` client endpoints themselves out of scope for this stage so Agent 06 can wire them onto the new middleware and access-resolution layer. ## Commands And Tests Run - `gofmt -w internal/app/app.go internal/db/models.go internal/db/apikeys.go internal/apikeys/context.go internal/apikeys/service.go internal/http/router.go internal/http/handlers.go internal/http/view_data.go internal/http/admin_api_keys.go internal/http/api_key_middleware.go internal/http/auth_integration_test.go internal/apikeys/service_test.go internal/http/api_key_middleware_test.go internal/http/api_keys_integration_test.go` - passed; - `GOCACHE=/tmp/go-build-agent05-2 GOMODCACHE=/tmp/go-mod-agent05-2 go test ./...` - passed after downloading dependencies with approval; - `GOCACHE=/tmp/go-build-agent05-build GOMODCACHE=/tmp/go-mod-agent05-2 go build -o /tmp/update-server-agent05 ./cmd/server` - passed; - `GOCACHE=/tmp/go-build-agent05-build2 GOMODCACHE=/tmp/go-mod-agent05-2 go build -o /tmp/update-migrate-agent05 ./cmd/migrate` - passed. ## Known Limitations - CSRF protection is still not implemented for admin forms, including the new API key creation, update, and revoke or activate actions; - the admin API key UI is intentionally minimal and functional rather than polished; - the one-time reveal happens on the direct POST response instead of a PRG redirect because the raw key must not be placed into query strings or persistent storage; - no live client `/api/v1` endpoints use the new middleware yet; the groundwork is ready but the actual project list, latest-release, and download endpoints remain for Agent 06; - expiration input currently accepts either empty, `YYYY-MM-DD`, or full RFC3339 UTC text rather than a more polished timezone-aware widget. ## Recommended Next Step Agent 06 should wire the new `requireAPIKey`, `requireAPIKeyPermission`, and `requireAPIKeyProjectAccess` middleware into the client `/api/v1` endpoints for accessible-project listing, latest release lookup, and authenticated artifact download. ## Notes For Validator - verify that only `key_prefix` and `key_hash` are stored in SQLite and that the raw key appears only in the immediate creation response; - verify that revoked or expired keys are rejected by `requireAPIKey` with `401` and that missing permissions or blocked project scope return `403`; - verify effective access resolution across all five scope modes, especially that archived projects do not appear in accessible-project results; - verify scope transitions clear the incompatible access rows so the existing migration guards continue to succeed; - verify the admin detail page preview matches the effective active project set for the key.