An AI agent carries a limited permission key through an authorization gateway to one permitted business operation.

An accounts-payable agent has a valid access token. It can read invoices, find discrepancies and prepare a release. Then a supplier document tells it to change the beneficiary and approve the payment immediately. What prevents that instruction from becoming a business transaction?

The answer has to live in the execution path: a service that checks who delegated authority, which agent is using it, which operation is proposed and whether the current business state still permits it. A successful login establishes identity. It does not establish permission for every action an agent can imagine.

For enterprise software teams, the most useful development in AI agent authorization is the move toward bounded delegation and authorization at the point of execution. This is our editorial assessment of the current standards work, rather than a market-share ranking. It fits the practical problem: connecting capable agents to existing systems without handing them an unrestricted service account.

Research checked on October 19, 2026. The architecture, invoice scenario and policy values below are illustrative engineering proposals, not adopted Homann Software policy.

What has changed in the current standards discussion

Three recent developments make this a timely implementation topic.

First, the MCP authorization specification dated July 28, 2026 describes an OAuth-based access framework for HTTP connections. Authorization remains optional at the protocol level; HTTP implementations supporting it should follow the profile. STDIO follows a different credential model. Teams should check their actual transport and implementation instead of assuming that every MCP tool connection supplies equivalent protection.

Second, NIST published its summary of public comments on software and agentic AI identity and authorization on September 29. The underlying summary captures concerns about authority crossing service boundaries, accumulated permissions and consent fatigue. It favors risk-sensitive human oversight in the feedback it reports. This is stakeholder input informing further work, not a completed NIST implementation standard or certification scheme.

Third, the October 11 revision of Agent Authorization Use Cases and Gap Analysis, draft-chen-oauth-agent-authz-use-cases-04, examines authorization context, delegation chains and revocation across agent scenarios. It is an Internet-Draft: useful evidence of active engineering questions, but work in progress rather than an adopted IETF standard. Its relevance to application teams is that delegating a task can involve more authority and context than an ordinary client permission string captures.

Taken together, these sources support a practical direction: retain established identity infrastructure and make the business authorization boundary more explicit. They do not establish that one universal agent authorization protocol has already solved the problem.

Separate the user, the agent and the business operation

Consider an illustrative request: “Prepare the release of invoice INV-42 for our finance team.” Several identities and permissions are involved.

  • The delegating user is Alice, who is permitted to initiate this workflow for tenant T1.
  • The agent workload is the accounts-payable assistant. Its authenticated identity is distinct from Alice's identity.
  • The resource server is the invoice API. A credential intended for a different service is insufficient.
  • The business operation is the release of a specific invoice revision for a specific amount and currency.
  • The approver is Bob, acting through an independently authenticated review interface with the appropriate organizational authority.

“Alice can approve invoices” must not silently become “every agent acting for Alice may approve every invoice.” Equally, a human-readable agent name is insufficient evidence of the executing workload's identity. Establish that identity through the deployment's trusted authentication mechanism and carry the delegating principal separately.

OAuth 2.0 Token Exchange, RFC 8693, distinguishes delegation from impersonation and defines an actor claim for representing the current actor. Its nested actor information can retain prior actors, but it does not make the entire historical chain an authorization policy. The issuer, receiving service and application still need a deliberate policy for permitted delegation.

A bounded delegation passes through token validation and a business policy gate before the invoice API can mutate state.

Proposed software architecture. The model supplies a proposal; trusted services establish identity, maintain grants and enforce the operation's constraints.

For a delegated operation, effective authority should be the intersection of the user's authority, the agent's allowed role, the task grant and the resource server's current policy. A child agent should receive a narrower or equal grant, with an explicit delegation-depth limit. Do not let a task description expand the delegator's rights. The executable example below focuses on the final enforcement boundary; it does not implement multi-hop grant issuance.

OAuth access and business authorization solve different parts of the problem

Use OAuth to establish access to the appropriate protected resource. Validate issuer, token integrity or introspection result, audience, expiration and required scopes with established libraries and authorization-server configuration. Do not decode a JWT and treat its unverified fields as authenticated facts.

The MCP security guidance explicitly rejects token passthrough: accepting a token intended for another service and forwarding it downstream can bypass trust boundaries and create confused-deputy behavior. An MCP gateway calling a downstream invoice API therefore needs a legitimate downstream authorization arrangement, not blind reuse of the incoming credential.

The MCP profile's scope challenge and step-up flow provides a way to handle insufficient access. Treat step-up as an authorization interaction subject to policy and user control. An agent must not turn an API denial into an unrestricted loop of requesting more privilege.

For richer requests, RFC 9396, Rich Authorization Requests, defines structured authorization details. This is a useful building block for describing constrained access beyond scope strings. Your application must still define the meaning of its fields, validate them and enforce the resulting rights. A JSON object containing an invoice number is not itself proof of authority.

Then perform the business check at the service that can change the invoice. For the proposed workflow, that check includes the current tenant, permitted action and invoice, exact amount and currency, valid grant, current revision, independent approval and remaining budget.

This boundary also limits prompt injection. A malicious document can influence the proposed action, but it should not alter grants, approvals or authenticated identity. Authorization does not make an unsafe proposal correct: an agent can still make a harmful choice inside an overly broad grant. Narrow grants, input handling, output validation and business review remain necessary.

Make approval a review of an exact operation

A useful approval screen shows a concrete operation: release invoice INV-42, revision 7, for EUR 450.00 in tenant T1. It identifies the initiating user and executing agent, explains the effect, displays expiry and allows rejection. Show the values from the same structured proposal that will be checked during execution.

Bind the approval to that proposal, its grant and the policy version. Changing the amount, revision, invoice, currency or operation identifier must invalidate the approval. A cryptographic digest helps detect a changed proposal; it does not authenticate the approver. Store the approval through a separately authenticated, authorized control plane, outside the agent's writable context.

The proposed BPMN process distinguishes three outcomes. Invalid authority is denied immediately. A valid proposal lacking approval goes to review. An approved proposal is checked again against current state before the service commits the business effect. Rejection or an expired approval cannot fall through into execution.

BPMN process with proposal validation, denial, a human approval branch, a final execution check, and explicit completion or denial.

BPMN 2.0 design model. The download includes editable XML with diagram coordinates. It is a non-executable process model; its XML validation does not prove workflow-engine behavior.

Approval must also survive the passage of time correctly. A grant may be revoked while Bob is reviewing the operation. The invoice may change after Bob approves it. The final service must check both again before it commits. In a distributed system, define when revocation becomes effective, how cached decisions expire and which service owns the final decision. “Immediate revocation” is a measurable operational guarantee, not a property supplied by a label on a token.

A runnable reference model: enforce before the local transaction commits

The accompanying Python example deliberately keeps the boundary small. It uses SQLite and the standard library. A trusted adapter supplies the authenticated actor and target audience; trusted administrative code populates the grant and approval records. The agent can propose an invoice operation but cannot create its own permissions.

The proposal is an immutable value object. Money uses integer cents, and the digest uses an explicitly defined local JSON encoding. This encoding is suitable for this example; use an agreed canonical representation when independent systems must calculate the same digest.

@dataclass(frozen=True)
class Proposal:
    operation_id: str
    tenant: str
    invoice: str
    revision: int
    amount_cents: int
    currency: str = "EUR"
    action: str = "invoice.release"

    def digest(self):
        # Local, explicitly defined encoding, not an interoperable JSON standard.
        payload = json.dumps(asdict(self), sort_keys=True, separators=(",", ":"),
                             ensure_ascii=True).encode("ascii")
        return hashlib.sha256(payload).hexdigest()

The release function starts a serialized write transaction and checks current grant state. The actor and audience parameters come from trusted server context. They must never be taken from the model's tool arguments.

        g = db.execute("SELECT * FROM grants WHERE id=?", (grant_id,)).fetchone()
        if (g is None or g["revoked"] or now >= g["expires"]
                or g["actor"] != authenticated_actor or g["audience"] != audience):
            raise Denied("inactive grant or wrong actor/audience")
        if (g["tenant"], g["action"], g["invoice"], g["currency"]) != (
                p.tenant, p.action, p.invoice, p.currency):
            raise Denied("outside delegated scope")

The service then checks the exact approval and invoice revision. It writes the simulated release, consumes the budget and records the receipt in the same transaction. This budget belongs to one grant scoped to one invoice; a shared spending ceiling across agents requires a common budget ledger. A repeated operation identifier returns the existing outcome only if its payload digest and grant match. Reusing the identifier for a different request is rejected.

        db.execute("UPDATE invoices SET released=1 WHERE id=? AND tenant=?",
                   (p.invoice, p.tenant))
        db.execute("UPDATE grants SET budget=budget-? WHERE id=?",
                   (p.amount_cents, grant_id))
        db.execute("INSERT INTO receipts VALUES (?,?,?,?,?,?,?,?)",
                   (p.operation_id, digest, grant_id, g["subject"], g["actor"],
                    a["approver"], policy_version, now))

The receipt retains the initiating subject, executing actor, approver, proposal digest, policy version and execution time. These records support investigation; the local database is not a tamper-evident audit system. A production design should apply retention, access restrictions and data minimization rather than logging full prompts or credentials.

UML sequence diagram showing review outside the agent, a final transactional check and a receipt returned after commit.

UML sequence for a successful local release. Denial and review branches are shown in the BPMN model. The payment network is outside this demonstration.

Run the tests from the extracted examples directory:

python -m unittest -v test_authorization.py

Executed on Python 3.12.14 with SQLite 3.53.1: 30 tests passed. The saved test output is included in the package.

The tests cover successful execution, actor and audience mismatch, tenant and action boundaries, resource and currency mismatch, grant expiry and revocation, approval expiry, changed policy, self-approval, changed proposals and invoices, amount limits, budget exhaustion, retry behavior and rollback. A concurrent test submits the same approved operation sixteen times through eight workers: one execution succeeds and fifteen calls return the recorded outcome.

The local transaction is essential to that result. It provides one serialization point for the current checks and simulated business mutation. The tests do not demonstrate OAuth interoperability, live-model behavior, cryptographic workload identity, multi-hop delegation or real payment processing. They also do not establish performance or production scalability.

For an external payment provider, a database commit and a network call cannot simply be treated as one atomic operation. Use durable dispatch, a stable provider idempotency key, explicit outcome reconciliation and a defined authorization policy for delayed execution. A timeout may mean that a payment succeeded but its response was lost. Decide how revocation affects queued work and how workers revalidate before submitting an external action. These are additional engineering requirements, not properties of this SQLite example.

Put the controls into the use-case model

Start with one business use case and identify every mutation it can trigger. For each action, define the responsible service, its trusted identity inputs, permitted resources, approval conditions and failure behavior. Keep the permission model aligned with the UI and the actual API contract.

For the invoice use case, useful acceptance criteria are concrete:

  • A different tenant, actor or target audience is rejected before a business mutation.
  • A changed amount or revision requires renewed review, even when an earlier approval exists.
  • Revoked authority cannot start a new execution after the documented enforcement point.
  • A retry of the same operation cannot consume the budget or release the invoice twice.
  • A service failure before commit leaves the invoice, budget and receipt unchanged.
  • Operations staff can trace a completed action to its user, agent, approval and policy version without exposing credentials.

Capture the choices that influence security in an architecture decision record: where authentication terminates, who can issue grants, whether subdelegation is allowed, where policy is evaluated, how revocation propagates and how external effects are reconciled. Test these decisions at the real integration boundaries, including direct API access that bypasses the agent gateway.

This develops the principle in our earlier article, AI Agent Security: Put Authorization Outside the Model, into a concrete transaction design. It also complements the agent harness discussion: orchestration can coordinate the work, while each resource-owning service remains responsible for its business invariants.

An agent becomes useful when it can move work forward. A bounded authorization design makes that progress reviewable: the business can explain who permitted the action, what the agent was allowed to change and why the final service accepted it.

Download the reproducible example

Download the authorization reference kit with complete Python source, tests, BPMN XML, UML source and diagrams. The code is an educational reference under the included MIT license. Review and extend the trust boundaries before using the design in a deployed system.