4f949e6d8f
API keys were never validated — the middleware only checked session tokens, so an X-API-Key request always 401'd. Add auth.Service.ValidateAPIKey (looks up the key hash, enforces enabled/revoked/expiry, loads the user + roles, stamps last_used_utc) and route X-API-Key / bearer auth through it. Add per-key scopes (migration 006): "read" (GET/HEAD only) or "readwrite" (full access, default). The middleware rejects mutating requests from a read-scoped key with 403. Create accepts a scope; list and create responses include it; the UI create dialog has a scope selector and the list shows a scope chip. Disable/re-enable and revoke (permanent) were already correct. Verified live: RW key GET/POST ok; read key GET ok, POST 403; disable→401, re-enable→200; revoke→401 and re-enable blocked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>