Mission-Governed Access

June 9, 2026 · View on GitHub

Mission Lifecycle

Scenario

An agent runs a multi-step task on the user's behalf, governed by a single approved mission. Throughout the task it mixes two kinds of authority:

  • Resource access (scopes) — reading and writing remote APIs, carried in auth tokens through the usual challenge → exchange → retry pattern.
  • Local actions (tools) — things the agent does itself, gated at the PS permission endpoint.

The PS evaluates each step against the mission's intent: fitting requests resolve silently, out-of-mission requests prompt the user, and once the mission is terminated everything is refused. This walkthrough ties together Missions, Mission Governance Clients, and Mission Governance (Server).

The flow at a glance

sequenceDiagram
    participant Agent
    participant PS as Person Server
    participant Resource as Mission-aware Resource

    Agent->>PS: 1. propose mission
    PS-->>Agent: mission blob + AAuth-Mission (approver, s256)

    Agent->>Resource: 2. GET /data (signed, AAuth-Mission)
    Resource-->>Agent: 401 + resource token (mission copied in)
    Agent->>PS: 3. exchange resource token
    Note over PS: scope fits intent → grant silently
    PS-->>Agent: auth token (mission echoed)
    Agent->>Resource: GET /data (auth token) → 200

    Agent->>PS: 4. permission: out-of-mission tool
    Note over PS: out of scope → prompt user
    PS-->>Agent: granted / denied

    Agent->>PS: 5. audit the action
    Agent->>PS: 6. propose completion
    Note over PS: user accepts → mission terminated

1. Propose the mission

The agent states its intent and the tools it wants pre-approved. The PS may run a clarification chat before approving.

var governance = new AAuthClientBuilder(key)
    .UseJwt(agentToken)
    .WithPersonServer("https://ps.example")
    .BuildGovernance();

MissionSession session = await governance.ProposeMissionAsync(
    new MissionProposal("Plan my weekend trip to Seattle.")
    {
        Tools = new[] { new MissionTool("add_to_calendar", "Add an itinerary item to the calendar.") },
    });

Mission mission = session.Mission;

2–3. Access a resource (scope evaluated in context)

Resource access uses the ordinary access flow with the AAuth-Mission header added. A mission-aware resource copies the mission into its resource token, so the PS sees the mission when it evaluates the requested scope. If the scope fits the mission's intent, the PS grants the auth token silently and remembers the decision for the rest of the mission.

// WithMission emits the AAuth-Mission header on every request and composes with
// the challenge handler, so the whole 401 → exchange → retry leg is automatic.
using var client = new AAuthClientBuilder(key)
    .UseJwt(agentToken)
    .WithPersonServer("https://ps.example")
    .WithMission(mission)
    .WithChallengeHandling()
    .Build();

// Challenge → exchange → retry happens transparently; the PS judged the scope
// against the mission intent during the exchange.
var response = await client.GetAsync("https://trips.example/trips");

A later request for a scope the PS has not seen and that does not fit the intent is deferred to the user (gate 2). See Token Issuance for how the resource and PS carry the mission claim through the tokens.

4. Request permission for a local tool

A tool is an action the agent runs itself. Pre-approved tools resolve locally; any other action goes to the PS, which prompts the user when it is out of mission.

// Pre-approved tool → granted silently.
var add = await session.RequestPermissionAsync(new MissionAction("add_to_calendar"));

// Out-of-mission tool → the PS prompts the user (gate 3).
var cancel = await session.RequestPermissionAsync(
    new MissionAction("cancel_booking"),
    description: "Cancel the existing hotel reservation the user flagged.");

if (!cancel.IsGranted)
{
    Console.WriteLine($"Not allowed: {cancel.Reason}");
}

5. Audit what happened

After acting, the agent reports it. Auditing always carries the mission and is fire-and-forget.

await session.RecordAuditAsync(
    new MissionAction("add_to_calendar"),
    description: "Added the flight and hotel to the user's calendar.",
    result: new JsonObject { ["items"] = 2 });

6. Close the mission out

When the work is done the agent proposes completion. The user accepts the summary, and the PS terminates the mission.

bool terminated = await session.ProposeCompletionAsync(
    "Planned the weekend trip: compared 3 flights and 2 hotels, saved the itinerary.");

If the PS's interaction relay cannot reach the user synchronously, it returns InteractionRelayResult { Pending = true }; the governance mapper then answers the completion proposal with a deferred 202 + poll Location (§Deferred Consent), and the agent's InteractionClient polls until the user accepts or declines — the same park-and-poll mechanics used for deferred permission consent.

After termination, any further governed request returns 403 mission_terminated, surfaced to the agent as AAuthMissionTerminatedException (see Error Handling).

The binding chain

Across all of these steps the mission travels as the same { approver, s256 } pair: declared on requests via the AAuth-Mission header, copied into the resource token by a mission-aware resource, and echoed into the auth token by the PS. The mission content never leaves the PS — only the pointer and its hash do.

Further reading