View all

Enforcing user intent across AI tool calls

In the first part of this blog series, Intent based access control: Whose intent is it anyway?, we saw that what mattered was the user/prompter’s intent, less so the Agent’s. We also saw that Intents could be formalized as access requests constrained to the domain of knowledge relevant to the Agent of Agentic workflow. Given that, we formalized intent as a set of OpenID AuthZEN evaluations statements.

The next step is to use that intent to decide which tools an agent can call. That requires translating the user’s request into the actions and constraints the system understands.

Let's have a look at the ubiquitous “Book a flight” example. In this use-case, we assume that the domain of knowledge the AI travel agent evolves includes a flight system that can search for flights but also book them. “Search” and “book” are verbs that are known to the system as valid actions, whereas other verbs such as, for example, “list”, “buy” or “reserve” are not part of that agent’s vocabulary.

Given this, the following prompt:

“Reserve a flight from Vancouver to Paris, in economy class, departing on December 20th and return January 4th, 2027”

Could be, for example, translated into the following intents:

[
  {
	“subject”: {
“type”: “User”,
“id”: “Alex”
},
“action”: {
	“name”: “search”
},
“resourse”: {
	“type”: “Flight”
},
“context”: {
	“departure_date”: “12-20–2026”,
	“return_date”: “01-04–2027”,
	“class”: “economy”
}
  },
  {
	“subject”: {
“type”: “User”,
“id”: “Alex”
},
“action”: {
	“name”: “book”
},
“resourse”: {
	“type”: “Flight”
},
“context”: {
	“departure_date”: “12-20–2026”,
	“return_date”: “01-04–2027”,
	“class”: “economy”
}
  }
]

It is important to note that the same intent could be represented in many different ways depending on the implementation’s model and access policies. The main point here is that the intent's formalization must match the system’s knowledge (or ontology). Intent needs to be extracted by an LLM, to which this ontology, policies, vocabulary or schema has been supplied as a system/context prompt. This grounding is critical to ensure that the intent is actually relevant.

How the gateway carries user intent between agents

Intent-based Access Control (IBAC) processing requires a specific architecture: it requires protecting all agents and resources in an agentic workflow with a Gateway, acting as a proxy for all requests. That proxy must understand the underlying protocol, and therefore act as a target resource for the client Agent, as well as a calling client on the resource side. The gateway can then enforce access controls, perform token exchange to record Subject-Actor delegations at every hop, and also ensure that the User’s intent is also carried, in a signed token, from an agentic hop to another.

The Gateway performs a Token Exchange flow with a RFC 8693-compliant Secure Token Service (STS) - such as the Indykite Token Service-, in order to keep track of the Subject to Actor Agent delegations at every hop in the agentic workflow. The user’s intent can be passed as a custom claim on each one of these exchanges, and carried from hop to hop.

For reference, an example of such an architecture was published in the Whitepaper: Agent Control Architecture Guide.

We now have a formal representation of the human Subject’s intent, carried around in a signed token from hop to hop.

Implementing intent-based access control

Extracting the intent from the user’s prompt or the task given to the agent is, and should be, the only non-deterministic process in the whole IBAC framework. So what happens next?

We know what the user intends to do, we must now ensure that the Agent’s actions match that intent. For this we will rely on a new profile currently being worked on (and almost ready) within the OpenID AuthZEN working Group: the  COAZ: A Framework for Mapping Information Models to AuthZEN Authorization Requests. This profile, and its binding for MCP,  COAZ-MCP: COAZ Binding for the Model Context Protocol provides a way to annotate MCP Server Tool and resource descriptors with CEL-enhanced AuthZEN mappings, to define how MCP JSON-RPC messages can be mapped into requests to the OpenID AuthZEN Authorization API. The goal is to enable MCP and AI gateways and servers to perform fine-grained, parameter-level authorization through an AuthZEN Policy Decision Point (PDP), before the request even reaches the MCP resources.

For IBAC, we can slightly enhance the semantics of these COAZ mappings to add this additional meaning: they can also represent a declaration of intended usage. For example, let’s consider the following COAZ-enhanced MCP Descriptor, taken from the COAZ-MCP binding profile itself:

{
  "tools": [
    {
      "name": "get_customer",
      "description": "Get customer details",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id":   { "type": "string", "description": "The customer identifier" },
          "case": { "type": "string", "description": "The case being worked on" }
        },
        "required": ["id"]
      },
      "_meta": {
        "net.openid.authzen/coaz-mcp": {
          "evaluation": {
            "subject":  { "type": "User", "id": "$token.sub" },
            "action":   { "name": "get_customer" },
            "resource": { "type": "Customer", "id": "$params.arguments.id" },
            "context":  { "case": "$params.arguments.case" }
          }
        }
      }
    }
  ]
}

The COAZ mapping is defined as the net.openid.authzen/coaz-mcp MCP Metadata ( _meta) field. In this case, the declared intended usage of the `get_customer` MCP Tools, is for a subject, whose identity comes from the Bearer Access Token’s `sub` claim ("$token.sub") , to perform an action called "get_customer", over a resource of type "customer", whose ID is provided as an input parameter in the request. Additional context filters, such as a case number here, can also be supplied as input parameters to the MCP tool call.

After resolution of the CEL expressions using the incoming request’s elements (including Bearer token), the resolved COAZ mapping becomes, for example:

      "_meta": {
        "net.openid.authzen/coaz-mcp": {
          "evaluation": {
            "subject":  { "type": "User", "id": "Alex" },
            "action":   { "name": "get_customer" },
            "resource": { "type": "Customer", "id": "CorpX" },
            "context":  { "case": "12345" }
          }

It now becomes possible to compare a human Subject’s intent, expressed as AuthZEN statements, with declarations of intended usage placed on protected resources, themselves also defined as AuthZEN statements through COAZ Mappings. Subject, action, resource and context filters can be compared deterministically, and access enforced at runtime. Moreover, an AuthZEN-Based IBAC system can also easily determine which tools from any given MCP server actually match a given User intent.

Taking our flight booking intent for example, it is easy to see that if the Flight Agent tried to call the `get_customer` MCP tool, the Action and Resource types would mismatch, and the request would therefore be denied. On the other hand, a Flight “Search” tool would match the intent:

User Intent vs Resource Mapping
User Intent Resource’s Intended Usage as COAZ mapping (after CEL resolution)
[
  {
    “subject”: {
      “type”: “User”,  ------Match-OK--->
      “id”: “Alex”    ------Match-OK--->
    },
    “action”: {
      “name”: “search” --No Match-FAIL-->
    },
    “resource”: {
      “type”: “Flight” --No Match-FAIL-->
    },
    “context”: {
      “departure_date”: “12-20-2026”,
      “return_date”: “01-04-2027”,
      “class”: “economy”
    }
  }
]
"_meta": {
  "net.openid.authzen/coaz-mcp": {
    "evaluation": {
      "subject": {
->        "type": "User",
->        "id": "Alex"
      },
      "action": {
->        "name": "get_customer"
      },
      "resource": {
->        "type": "Customer",
        "id": "CorpX"
      },
      "context": {
        "case": "12345"
      }
    }
  }
}
[
  {
    “subject”: {
      “type”: “User”,  ------Match-OK--->
      “id”: “Alex”    ------Match-OK--->
    },
    “action”: {
      “name”: “search” ------Match-OK--->
    },
    “resource”: {
      “type”: “Flight” ------Match-OK--->
    },
    “context”: {      ------Match-OK--->
      “departure_date”: “12-20-2026”,
      “return_date”: “01-04-2027”,
      “class”: “economy”
    }
  }
]
"_meta": {
  "net.openid.authzen/coaz-mcp": {
    "evaluation": {
      "subject": {
->        "type": "User",
->        "id": "Alex"
      },
      "action": {
->        "name": "search"
      },
      "resource": {
->        "type": "Flight"
      },
->      "context": {
        "departure_date": "12-20-2026",
        "return_date": "01-04-2027",
        "class": "economy"
      }
    }
  }
}

Orchestrating intent and authorization

As we’ve seen, the IBAC engine compares the AuthZEN representations of the User’s intent to the Resource’s declared intended usage. The only requirement here is for tools and resource developers and implementers to add a COAZ mapping to their resource descriptors.

Note that a similar method can be used and applied to A2A Agent Skills. These Agent Skills are documented in the A2A Agent Cards of these agents, and can therefore also be augmented in the same way by COAZ-like mappings.

In any case, the IBAC check must additionally be augmented by a more traditional authorization check. This can be accomplished by the Gateway proxy, acting as a Policy Enforcement Point for both authorization and Intent checks. The flow such a Gateway must implement in order to control access to any protected tool or resource must therefore be:

Tool discovery:

  1. The Client agent makes a request to List the tools of a target MCP Server. The request contains the full `act` delegation flow and User intent.
  2. The Gateway fetches the list of Tools from the target MCP server
  3. It filters out the target resources using a standard Resource Search AuthZEN call.
  4. It uses the Intent process described above to further filter out the authorized resource list down to only those target resources that match the user’s intent.
  5. The resulting filtered list is returned to the agent. The unauthorized or irrelevant resources are hidden.

Specific tool call:

The same process applies when the client Agents makes an actual specific Tool call. In that case, the only difference is that instead of performing an AuthZEN Resource search, the gateway makes a simple AuthZEN Evaluation request to the PDP, and if the access is granted, it then also ensures that the intents match.

Scaling agent autonomy through intent-based control

Intent-based access control turns AI unpredictability into predictable, manageable authorization rules. By combining open standards like AuthZEN with dynamic authorization engines, organizations can safely empower autonomous agents without sacrificing security, governance, or control.

Ready to bridge the gap between user intent and enterprise policy? Explore Indykite today to discover how our Agent Control platform delivers seamless, dynamic authorization across your agentic workflows.

In this article

Keep updated

Subscribe

More from the Blog

Intent based access control: Whose Intent is it anyway?

Intent-based access control checks agent actions against the user’s original goal. Learn why Subject intent beats Agent intent and how AuthZEN formalizes it.

Meta's Muse and the enterprise risk of AI agent access you can’t see

When AI agents borrow a user’s identity, their actions become harder to trace. Explore what Muse reveals about enterprise visibility, delegated authority, and control over agent actions.

Intent-based access control for AI agents

Intent-based access control (IBAC) governs what AI agents can do and why. Explore how task intent shapes authorization across data, tools, and workflows.

Resources

Blog

Enforcing user intent across AI tool calls

Next

Guides & Whitepapers

The Enterprise Guide to EU AI Act Compliance

Next

News

Breakthrough AI wellbeing platform movemove selects IndyKite to power trusted AI

Next