Run Authorization and Capability Tokens
Authorize one immutable deployment before execution, keep broad credentials out of the runtime, and issue short-lived proof for exactly one downstream action.
The enterprise problem and today’s slice
Enterprise problem: If Northstar starts the HelixWorks Supplier Onboarding Agent from a valid session and gives its runtime reusable connector tokens, one stale membership, prompt injection, or compromised dependency can become broad and persistent enterprise access.
Whole-course context: The previous slice produced Alice’s authenticated principal, current Marketing context, app binding, and separately owned service and personal grants; today consumes those facts at run admission without treating any one of them as sufficient.
Today’s slice: We authorize one immutable deployment, require workload identity as a second key, exchange authority across narrow audiences, mint one action-bound capability token, and bound revocation freshness across provider, runtime, and connector boundaries.
End-of-day evidence: Acme receives an allowed run, denied cross-team run, two-key workload proof, changed-argument and replay denials, and mid-run revocation result with complete immutable evidence.
Still unsolved: Model Context Protocol (MCP) discovery, detailed tool and argument policy, human approval, nested agent delegation, source-data trimming, and production infrastructure remain outside this slice.
Thesis: A run token is proof that one subject may start one deployment; it becomes safe downstream authority only after a trusted workload presents it and a gateway narrows it into a single-use action capability.
Smallest complete model: Admit, bind, narrow. Northstar first admits Alice to the Procurement deployment, binds that decision to the attested Supplier Onboarding workload, then narrows one proposed supplier-system change into proof the connector adapter can verify.
This model prevents two common category errors: run admission is not tool permission, and workload identity is not human delegation. Both are necessary before the gateway can mint a capability for one side effect.
Customer outcome and implementation focus
The customer outcome is a reliable, reviewable implementation of 06 run authorization capability tokens. This day introduces the mechanism before policy detail and evidence review; it does not repeat the same customer stories in prose, tables, and diagrams.
Components in focus
Authorization policy service owns decisions; the connector/runtime gateway owns enforcement. Compute: API and isolated worker processes. Storage: PostgreSQL is authoritative for grants and state; Redis is a versioned cache; vault owns secrets; object storage retains redacted evidence only.
Implement the mechanism
Implement the day’s boundary with a current, explicit decision before privileged compute or a downstream call. Bind every effect to a tenant, subject or workload, deployment, resource, and short-lived evidence ID; a cache or model response never grants authority.
Failure modes, trade-offs, and decision rules
Capability systems fail when a broadly reusable token is renamed “capability” without actually narrowing what the holder can do. Acme must choose freshness and token granularity according to consequence.
Reusable decision rule: Admit one immutable run from current facts, require workload and delegated authority as separate keys, then narrow every trust-boundary hop in audience, resource, arguments, lifetime, and replay semantics.
| Failure or trade-off | Consequence | Reusable decision rule |
|---|---|---|
| Run token accepted directly by adapter | Run admission becomes arbitrary tool access | Exchange at each trust boundary and require exact service audience |
| Workload identity without delegation | Any trusted pod can act for any user | Require workload identity AND current run delegation |
| Capability omits canonical argument digest | Runtime changes channel or body after allow | Bind normalized arguments and reject any mismatch |
| “Single-use” check is non-atomic | Concurrent replay duplicates side effect | Store nonce consumption atomically before provider call; add idempotency key where provider supports it |
| Revalidate every fact on every low-risk read | Strong freshness but high latency and owner-service dependence | Use versioned bounded caches for reads; reload immediately for consequential writes |
| Cache until token expiry for high-risk write | Fast path preserves revoked authority | Risk sets freshness: higher consequence means shorter cache and later final check |
Implementation and verification
An apparently valid token chain may still accept the wrong workload, audience, arguments, or replay, so implementation proceeds from durable decision to adapter verification.
- Persist the full run intersection and decision ID before allocating the Campaign Launch runtime.
- Mint a one-time admission for
agent-runtime; verify attestation and deployment/environment binding before exchanging it fortool-gatewaydelegation. - Keep provider credentials behind the broker and give the runtime no Vault route or minting key.
- Canonicalize the Slack intent, persist the tool decision, then mint a seconds-lived capability for exact adapter, connector, channel, digest, nonce, and decision.
- Atomically consume the nonce at the adapter before secret retrieval; verify audience, workload channel, digest, expiry, and current revocation state.
- Publish versioned revocation events and define measurable freshness objectives for low-risk reads and high-risk writes.
Verify an allow and these independent denials: Finance deployment, copied run token, trusted workload without delegation, wrong capability audience, changed channel, changed text, expired capability, concurrent replay, and membership removal before the next write. Each denial needs a fresh valid positive control.
Where the audience-narrowing hop uses OAuth token exchange, RFC 8693 defines subject-token, actor-token, audience, and act semantics. The single-action adapter capability is a platform security object, so its additional resource, argument-digest, nonce, atomic-consumption, and revocation invariants remain explicit platform policy rather than implied OAuth behavior.
Practical next action and falsifiable evidence
The next useful step is not adding another token type; it is proving that Acme’s existing three-box chain cannot be widened. Run one HelixWorks Supplier Onboarding Agent test that records the observed admission, workload exchange, original Slack post, changed-channel replay, and mid-run membership removal.
The thesis is falsified if compute starts before a durable allow, either key admits alone, any service accepts a token for another audience, changed arguments pass the adapter, a nonce is consumed twice, or Alice posts after revocation beyond the stated objective. Passing evidence shows one run decision narrowed into one workload-bound, action-bound, single-use effect.
HelixWorks repository lab
The run boundary lives in services/run-orchestrator/src/domain/run.ts:
public consume(costUsd: number): void {
this.assertRunning();
if (this.#stepsUsed + 1 > this.data.maxSteps ||
this.#costUsd + costUsd > this.data.maxCostUsd) {
throw new RunBudgetExceededError('Run budget exceeded');
}
this.#stepsUsed += 1;
this.#costUsd = Math.round((this.#costUsd + costUsd) * 100) / 100;
}
The declared intent is bounded execution, not a reusable bearer credential. Node interprets the aggregate; run counters change; CPU and memory execute the check; the snapshot and rejected command are evidence. The aggregate owns run invariants (SRP), repositories and clocks are injected (IoC/DI), and HTTP and event paths reuse the same budget rule (DRY). PubSub carries completed-run facts but cannot bypass admission.
pnpm --filter @helixworks/run-orchestrator test
Consume the final permitted step, attempt one extra step, cancel, and attempt another consume. Expect one budget denial and one state denial without a connector decision. An extra accepted step or post-cancel side effect falsifies the boundary.