Durable agent auth — roadmap
Spec freeze: DURABLE-AGENT-AUTH-SPEC.md (2026-07-12)
Branch (thinking): feat/durable-agent-mcp-auth-thinking
Branch (Phase A build): feat/durable-mcp-oauth-refresh
Owner approval required before any Build phase marked Auto starts.
Phase routing
| Phase | Name | Mode | Status |
|---|---|---|---|
| 0 | Thinking freeze (this track) | Thinking | DONE |
| A | Durable MCP OAuth refresh + Hermes spike | Thinking spike → Auto Build | DONE (tests green; Rank 1↔2 swap after spike) |
| B | Hub “Connect cloud agent” UX (device code primary after spike) | Thinking (UX freeze) → Auto | TODO |
| C | Scoped agent credentials (REST) + revoke | Thinking (token shape) → Auto | TODO |
| D | Propose-only / path-prefix scopes for marketing agents | Thinking → Auto | TODO |
| E | Marketing + docs honest positioning (with code PR) | Auto (with A/B/C) | TODO |
Never Outline/Plan on Auto. Never mark DONE without green required tests.
Phase 0 — Thinking freeze
DoD: Spec answers all design questions; recommendation + interim labeled; Build-ready Phase A prompt in OVERSEER handover.
Status: DONE.
Phase A — Durable MCP OAuth refresh + Hermes spike
Mode: Spike (Thinking, short) then Auto Build against frozen interfaces below.
Status: DONE (2026-07-12).
Spike (HARD GATE — completed)
- Upstream Hermes:
auth: oauth, token cache, headless paste-back — supported (docs + PR #5420). - Hostinger Managed Hermes version: unverified this session → spike verdict partial.
- Rank 1 ↔ Rank 2 swap applied: Phase B device authorization is primary for headless Hostinger; Phase A durable MCP OAuth remains shipped for Cursor + OAuth-capable Hermes.
- Evidence:
docs/evidence/durable-agent-auth/hermes-oauth-spike-2026-07-12.md.
Frozen interfaces (Build) — implemented
- Reuse existing store —
KnowtationOAuthProvidertakescreateGatewayRefreshStore({ consistency: 'strong' })(same instance as native OAuth on persistent host). - Strong consistency — file backend; blob prohibited for MCP (and for non-Netlify gateway refresh store).
- Lifetimes: access 3600s; refresh
DEFAULT_TOKEN_TTL_MS(30d); familyDEFAULT_FAMILY_TTL_MS(90d). - MCP OAuth 2.1 discovery/token unchanged for Cursor Sign-in.
- Public URL
https://mcp.knowtation.store/mcp. - Refresh
meta.agent(+client_id/scopes) for multi-Hermes revoke. - Offline-lock:
shouldMountDurableAgentAuth— endpoints unmounted; documented.
DoD checklist
- [x] Gateway restart does not invalidate unexpired MCP refresh families (integration test).
- [x] Unit + integration + e2e + security + data-integrity + security-stress tests.
- [x] Scope-aware REST:
mcp_accessvault:readcannot write (access-token-authz+getUserId). - [x] Offline-lock documented + asserted.
- [x] Hermes spike notes (no secrets).
- [x]
docs/AGENT-INTEGRATION.mdalways-on section in same PR as code.
Test tiers
| Tier | File(s) |
|---|---|
| unit | test/durable-mcp-oauth-unit.test.mjs |
| integration | test/durable-mcp-oauth-integration.test.mjs |
| e2e | test/durable-mcp-oauth-e2e.test.mjs |
| security | test/durable-mcp-oauth-security.test.mjs |
| data-integrity | test/durable-mcp-oauth-data-integrity.test.mjs |
| security-stress | test/durable-mcp-oauth-security-stress.test.mjs |
Phase B — Hub “Connect cloud agent”
Mode: Thinking (wireframes + device-code vs guided OAuth) → Auto.
Priority: Primary for headless Hostinger after Phase A spike Rank swap.
Frozen product goal
A non-SSH user completes “connect my cloud agent to my vault” in one Hub flow (device code preferred when loopback impossible).
DoD
- Settings → Integrations → Connect cloud agent
- Issues user_code / verification URL or deep-links Hermes MCP OAuth steps
- Agent ends with refreshable credential (MCP and/or agent refresh)
- Revoke from same panel
- Docs + Hub copy updated in same PR
Test tiers
unit (device code store), integration (poll → token), e2e (Hub UI happy path), security (code brute-force limits, single-use).
Phase C — Scoped agent credentials (REST)
Mode: Thinking (JWT/kt_agent_ prefix shape, OpenAPI) → Auto.
Frozen invariants
- Scoped, rotatable, vault-bound, Hub-revocable
- Default: no admin; prefer propose-only option
- Amends
HUB-API.md“no API-key-only path”
DoD
- Mint once + list + revoke APIs + Hub UI
- REST accepts credential; MCP optional bridge
- Seven-tier tests for credential module (Aaron standard)
Phase D — Propose-only + path prefix
Mode: Thinking → Auto.
- Agent may create proposals under
projects/<slug>/**without directPOST /notes - Enforce in gateway + MCP ACL
- Hard dependency: §8 confused-deputy scope-elevation closed in Phase A for
mcp_accesson REST mutating methods. Do not advertise propose-only / path-prefix scopes until remaining role-elevation edges (if any) are closed in Thinking freeze for D.
Phase E — Marketing honesty
Ship with whichever of A/B/C lands first that changes the user-visible connect story. No docs-only PR to main. Phase A docs ship with this code PR.
Build status table
| Phase | Status | Notes |
|---|---|---|
| 0 Thinking freeze | DONE | Spec + this roadmap |
| A Durable MCP OAuth | DONE | Strong store + scope guard + spike partial → Rank swap |
| B Connect agent UX | TODO | Primary for Hostinger after swap |
| C Agent credentials | TODO | |
| D Propose-only scopes | TODO | Depends on A scope guard (landed) |
| E Marketing/docs | TODO | With code PR |