Skip to content

Latest commit

 

History

History
179 lines (150 loc) · 6.46 KB

File metadata and controls

179 lines (150 loc) · 6.46 KB

Basic Authorization

Explanatory documentation only. This is not production code, a normative protocol definition, a Consumption implementation, or an executor.

What problem does this example address?

This example shows the Phase 6 path from one exact eligible policy decision to structural Authorization evidence and pure validation. Every SecureToolKit symbol shown is public. Variables such as evaluationInput are controlled outputs retained by the Host from earlier public transitions.

Why this flow?

An eligible policy decision is evidence, not Authorization. Issuance must repeat the frozen checks, and later validation must compare the submitted artifact against expectations retained independently by the Host. Consumption and Execution occur only after this example ends.

Architecture diagram

flowchart LR
    P["Untrusted ToolProposal"] --> C["CanonicalRequest"]
    H["Authenticated Host context"] --> I["EvaluationInput"]
    C --> I
    I --> D["PolicyDecision: allow"]
    D --> A["AuthorizationIssuer"]
    A --> Z["Authorization evidence"]
    Z --> V["AuthorizationValidator"]
    V --> R["Validation result"]
    R --> S["Host atomic Consumption"]
    S --> E["Host Execution"]

    subgraph STK["SecureToolKit"]
        C
        I
        D
        A
        Z
        V
        R
    end
Loading

Consumption and Execution are shown only to locate the boundary. This example does not implement either one.

Sequence diagram

sequenceDiagram
    participant Host
    participant Policy as PolicyEvaluator
    participant Issuer as AuthorizationIssuer
    participant Validator as AuthorizationValidator
    participant Store as Host Consumption store
    participant Tool as Host executor

    Host->>Policy: exact EvaluationInput + PolicySnapshot + boundary
    Policy-->>Host: eligible allow PolicyDecision
    Host->>Issuer: exact decision, snapshots, IDs, time, boundary
    Issuer-->>Host: Authorization
    Host->>Validator: Authorization + independent context + explicit time
    Validator-->>Host: AuthorizationValidationResult
    Host->>Store: atomically consume complete binding
    Store-->>Host: consumed exactly once
    Host->>Tool: execute outside SecureToolKit
Loading

Minimal Swift snippets

The Host first issues one exact Authorization. An allow decision alone is not Authorization.

import SecureToolKitCore

let authorization = try AuthorizationIssuer.issue(
    hostCapabilityBoundary: hostBoundary,
    id: try AuthorizationID(validating: "authorization-1042"),
    replayID: try AuthorizationReplayID(validating: "replay-1042"),
    consumptionID: try AuthorizationConsumptionID(validating: "consume-1042"),
    generation: try AuthorizationGeneration(1),
    decision: policyDecision,
    evaluationInput: evaluationInput,
    registrySnapshot: registrySnapshot,
    policySnapshot: policySnapshot,
    issuedAt: issuanceTime,
    lifetimeRequest: try AuthorizationLifetimeRequest(
        expiresAt: authorizationExpiry,
        maximumLifetimeSeconds: 300
    )
)

The Host constructs expectations from values retained independently before it accepts a submitted Authorization.

let validationContext = AuthorizationValidationContext(
    authorizationID: try AuthorizationID(validating: "authorization-1042"),
    version: .v1,
    generation: try AuthorizationGeneration(1),
    policyDecision: policyDecision,
    evaluationInput: evaluationInput,
    canonicalRequest: evaluationInput.canonicalRequest,
    toolDefinition: evaluationInput.toolReference.definition,
    registrySnapshot: registrySnapshot,
    policySnapshot: policySnapshot,
    subjectID: evaluationInput.securityContext.subjectID,
    tenantID: evaluationInput.securityContext.tenantID,
    sessionBinding: evaluationInput.securityContext.sessionBinding,
    delegationID: evaluationInput.securityContext.delegationID,
    scope: expectedScope,
    lifetime: AuthorizationLifetimeExpectation(
        issuedAt: issuanceTime,
        expiresAt: authorizationExpiry,
        maximumLifetimeSeconds: 300
    ),
    replayID: try AuthorizationReplayID(validating: "replay-1042"),
    consumptionID: try AuthorizationConsumptionID(validating: "consume-1042")
)

let validation = try AuthorizationValidator.validate(
    authorization,
    hostCapabilityBoundary: hostBoundary,
    context: validationContext,
    evaluationTime: validationTime
)

validation.reference and validation.consumptionBinding are evidence. They do not reserve, consume, persist, or execute anything.

Expected lifecycle

  1. The Host retains one authenticated HostCapabilityBoundary.
  2. Public registry, schema, context, intent, and lineage validators produce one exact EvaluationInput.
  3. PolicyEvaluator produces an eligible .allow decision.
  4. AuthorizationIssuer repeats the frozen checks and constructs one Authorization or throws without partial output.
  5. The Host supplies independently retained expectations and an explicit validation time.
  6. AuthorizationValidator validates deterministically and non-consumingly.
  7. A future Host store atomically consumes the complete binding exactly once.
  8. Only after successful Consumption may the Host execute its tool.

Threats prevented

  • Canonical argument or Tool Definition substitution rejects exact validation.
  • Subject, tenant, session, or delegation substitution rejects.
  • Capability or resource widening and narrowing reject exact scope equality.
  • Wrong Authorization, replay, or Consumption identity rejects.
  • Expired or invalid lifetime rejects using explicit Host-supplied time.
  • A parallel Host boundary rejects even when descriptive claims are identical.

Durable duplicate-use prevention is not performed by validation; it requires the Host's atomic Consumption store.

Common mistakes

  • Treating PolicyDecision.outcome == .allow as Authorization.
  • Building validation expectations from the submitted artifact instead of independently retained Host state.
  • Creating a new HostCapabilityBoundary for validation.
  • Treating successful validation as Consumption.
  • Executing before atomic single-use Consumption succeeds.
  • Logging raw prompts or tool arguments when handling an error.

Related documentation