Skip to content

Agent authorization: IAM for AI agents

Every AI agent you connect to Shield360 has an identity (Govern → Agent access). Agent authorization gives that identity one permission model, and makes sure the agent can only do what your organisation intends:

StepWhat Shield360 does
DefineOne profile per agent: an owner and a purpose (both required), a risk tier, and what it may use across six dimensions. Anything not listed is denied.
EnforceThe MCP gateway, the data gateway and Shield360’s AI proxy ask the same decision function before the agent acts, and record the answer. The AI proxy decides models and spend for every call that carries the agent’s token (see What is enforced where).
ElevateAn agent that lacks a scope can ask for it. Someone who is not the requester, not the agent’s owner or creator and not the person it acts for approves it for a limited time.
ReviewEach agent’s grants are compared with what it actually used. Its owner removes what it does not need and attests the rest. Overdue reviews raise alerts.
CoverEvery AI agent the environment runs, whether registered in the gateway or only seen in telemetry, is listed with the person accountable for it. Agents with no owner, or whose owner has left, are flagged.
ProveDecisions, elevations, reviews and ownership coverage are evidence for ISO/IEC 42001 and the EU AI Act, in the controls and in the evidence package.

Agent authorization is part of the Security module. Open it at Govern → Agent access → Agent authorization (/agent-authorization).

To let an agent pay on a person’s behalf within limits they set, and hand merchants a signed proof of that authority, see Agent mandates.

Agent authorization governs your own agents. To check the agents of other organisations that call your APIs and MCP servers with an agent passport, decide under your own policy and keep the evidence, see Inbound agents.

To give an agent a signed passport that tells another company’s API or MCP server which agent is calling, who runs it and whether it acts for a person, see Agent passports.

DimensionWhat it saysWhere it is kept
ToolsMCP services and their tools, with action scopes: read, write, delete. A grant names the tools, or says explicitly that every tool of the service is allowed (allTools), the actions allowed, why, and optionally when it lapses.The agent’s grants
DataData-gateway tables and data classes, released clear or masked, for stated purposes.The agent’s data authorizations
ModelsApproved model names or patterns, such as gpt-4o-mini or claude-*. Also limited by the environment’s approved-model list.The profile
DestinationsExternal hosts the agent may reach, such as api.github.com or *.example.com for subdomains.The profile
SpendDaily and monthly limits in USD. An agent with no limit at all may not spend.The profile
Run contextThe deployment environments the agent may act in, such as production. * allows any.The profile

A tool’s action scope comes from the tool itself: its MCP annotations (readOnlyHint, destructiveHint), the HTTP method of a wrapped API, then the verb its name starts with (list_, get_ read; delete_, remove_ delete). A tool whose effect cannot be shown to only read needs write.

Every enforcement point calls one decision function with the agent’s current state. The first rule that answers wins:

The agent itself

A pulled kill switch or a revoked token denies everything.

Where it runs

The run context must be one the profile lists. A call that names none runs in default.

Whom it acts for

When the agent acts on behalf of a person Shield360 knows, it may do at most what that person may have an agent do (see On-behalf-of access). Both identities are recorded.

The dimension

The tool grant and its action, the data authorization and its classes, the approved model and the spend limits, or the approved destination.

Each decision is allow, deny or needs approval. Needs approval means the agent lacks a scope that it may ask for: a tool or action it is not granted, a model or a destination not on its list. Spend limits, data classes, run contexts and the kill switch are never elevated.

Every decision is written to the decision log with the enforcement point, what was asked for, the outcome, a reason code and the policy version: a fingerprint of everything that can change the answer. Arguments, prompts and results are never recorded.

PointWhat it decides
MCP gateway (/api/mcp)Every tool call: the tool and its action scope. Refused calls tell the agent why.
Data gateway (data.query)Every governed read: the table and the classes of the fields it would return.
AI proxy (shield360 proxy serve, the container and the hosted proxy)Every model call that carries the agent’s token: the approved models, the environment’s list and the spend limits. See Enforcement at the AI proxy.
Check API (/api/agent-authorization/check)The decision the AI proxy asks for. Your own proxy or SDK wrapper can ask it too, before a model call or an outbound destination.
DimensionEnforcedHow
Tools and their actionsYesThe MCP gateway decides every tool call itself.
DataYesThe data gateway decides every governed read itself.
Models and spendYes, at the AI proxyShield360’s AI proxy (local, container and hosted) decides every model call that carries the agent’s token, refuses what is denied and counts what is allowed. An agent that reaches a model directly, or without its token, is not decided. Your own proxy can call the check API instead.
DestinationsAdvisory unless your proxy calls the check APIThe AI proxy serves only model providers, so no Shield360 component asks about other hosts. The MCP and data gateways reach only resources an administrator registered, and their tool grants and data authorizations govern them.

The evidence check says the same: models and spend enforced at the AI proxy, destinations advisory.

An agent marks its model calls through the AI proxy as its own by sending its Shield360 token in the X-Shield360-Agent-Token header, the same header the MCP gateway accepts. The proxy removes the header before forwarding, never logs it, and asks the check API for each call. See Agent authorization in the AI proxy for the headers and responses.

  • Allow forwards the call and counts it against the agent’s spend limits. Allows are never reused, so a kill switch or a revoked token stops the next call.
  • Deny refuses with 403 and agent_not_authorized. Needs approval refuses with agent_needs_approval, and the agent can ask for the scope through request-access. A refusal is reused for 30 seconds for the same agent, model, environment and person.
  • The environment is bound. The proxy proves which environment it enforces for: its collector token, or for the hosted proxy the service secret and the proxy key in the base URL. An agent token from another environment is refused (agent_tenant_mismatch). Nothing in the request chooses the environment.
  • When Shield360 can’t be reached, the proxy follows the AI policy’s fail mode. It refuses when guardFailClosed is on with prompt protection set to block. Otherwise it forwards with a warning. When the check API answers 429 for an agent, the proxy refuses the call: sending many calls never opens the fail mode.

Every decision the platform makes is in the decision log under the enforcement point AI proxy. Refusals and fail-open warnings are also reported as guard decisions named agent-authorization.

The MCP gateway, the check API and the AI proxy read two optional headers:

HeaderMeaning
X-Shield360-On-Behalf-OfThe person the agent acts for: an email or a Shield360 user id. Asserted, not verified: anyone holding the agent’s token can name anyone. It narrows what the agent may do (see on-behalf-of access) but never makes that person accountable for, or able to approve, an elevation.
X-Shield360-EnvironmentThe run context, such as production.

A JSON-RPC batch to the MCP gateway carries at most 20 messages; a larger one is refused whole.

An AI proxy (or any component that holds the agent’s token) asks before a model call:

Terminal window
curl -X POST https://app.shield360.ai/api/agent-authorization/check \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "X-Shield360-Environment: production" \
-H "Content-Type: application/json" \
-d '{ "kind": "model", "model": "gpt-4o-mini", "provider": "openai", "inputTokens": 1200, "maxOutputTokens": 800 }'
{ "outcome": "allow", "reason": "model_approved", "message": "The model is approved for this agent and within its spend limits.", "policyVersion": "3f9c2a1b7d40", "decisionId": "…", "countedCostUsd": 0.00066 }

For a destination, send { "kind": "destination", "host": "api.example.com", "method": "POST" }. Every decision is a 200 with an outcome, so a proxy reads one shape.

A proxy can also bind the check to its environment by sending its collector token in X-Shield360-Collector-Token. Shield360 then refuses an agent from another environment with 403 and code agent_tenant_mismatch, and a collector token that is not valid with 401 and code enforcement_point_rejected. An agent token Shield360 does not know, or one that was revoked, is 401 with code agent_token_invalid.

What a model call costs. Send the call’s inputTokens and maxOutputTokens: Shield360 prices the call itself from the environment’s model prices (Manage Models) and counts that against the agent’s daily and monthly limits. An estimatedCostUsd you send is only a floor: the higher of the two counts. A call Shield360 cannot price, with no positive estimate, has an unknown cost and is denied (cost_unknown): a missing or zero estimate never counts as free. The spend check and its record are one atomic step per agent, so calls made at the same moment cannot together pass a limit, and a call whose spend cannot be recorded is denied (spend_unrecorded).

Models and providers. A model rule that names a provider (openai/gpt-4o, anthropic/*) matches only calls for that provider. When the environment’s approved-model list names providers, a call must say its provider (provider, or a prefix such as openai/gpt-4o) to pass it. If the list cannot be read, model calls are denied (org_list_unavailable).

When a call needs approval, the agent can ask for the scope it lacks:

  • through the MCP gateway’s request_access tool: { "name": "github.create_issue", "action": "write", "justification": "…", "hours": 8 }
  • or POST /api/agent-authorization/request-access with the agent’s token, for agents behind the AI proxy (kind may be tool, model or destination)

A person can also ask for an agent from its Elevations tab. An agent’s request belongs to the agent’s owner; the person named in X-Shield360-On-Behalf-Of is shown as asserted by the agent, never as the requester. The request raises an agent_authorization.elevation_requested alert.

A request names exactly one tool (service.tool), model or host: patterns and wildcards such as * or claude-* are refused, so an approval never grants more than it names. An agent may file at most 10 requests an hour and have at most 20 waiting.

An approver with Approve agent elevations decides it for a number of hours (at most 30 days). Separation of duties follows AI intake: nobody decides their own request, and nobody approves an elevation for an agent they own, created or enrolled, or that would act for them (verified or asserted). Approval never widens a standing grant: the elevation itself allows the scope until it lapses, or, when the agent held no live grant on that service, a grant is created (or the expired one renewed) that lapses with it. Approval and the kill switch never interleave: an approval made as the switch is pulled is either refused or revoked by it.

Kill switch on an agent revokes, at once and on every gateway: its token, every tool grant (expired now and kept for the record), every data authorization (disabled), every approved elevation (lapsed) and every open request (cancelled). It asks for a reason, is audited and raises a critical agent_authorization.kill_switch alert.

Clearing the switch gives nothing back: rotate the agent’s token in Agent access and grant again what it needs. The token cannot be rotated while the switch is on. An agent that was never enrolled can be killed too: it is given a profile recording the switch, with its creator as owner.

When an agent acts for a person, the effective permission is the intersection of the agent’s grants and what that person may have an agent do. Shield360 reads the latter from the person’s organisation role:

PermissionLets an agent acting for this person…Shipped roles
Let agents read for me (agent_delegation.read)use read scopesAdministrator, Compliance officer, Analyst, Member, Viewer
Let agents change things for me (agent_delegation.write)use write scopesAdministrator, Analyst, Member
Let agents delete for me (agent_delegation.delete)use delete scopesAdministrator

The person’s permission never widens the agent’s grants. For a person Shield360 does not know, the agent’s grants alone decide and the log keeps a one-way reference instead of the address; turn on Refuse calls for people Shield360 does not know in the profile to deny them.

Each enrolled agent is reviewed every review interval (90 days by default). The Reviews tab lists unused access from the grant-versus-use view: idle agents, grants never used, tools never called, and grants to every tool of a service when only some are used. The agent’s owner, or anyone with Attest agent access reviews, removes what is not needed and attests the rest. The review records the suggestions as they stood, what was removed and the policy version left in force.

A review past its due date is flagged on the agent and raises an agent_authorization.review_overdue alert once per due date. More than two weeks late, it is a gap in the controls.

An enrolled agent’s owner must be an active member of the organisation. An owner is no longer active when:

  • they are removed from the organisation, by hand or by a mirrored team removal;
  • their SCIM provider deactivates or deletes them (also when Shield360 kept their membership because they are a protected account);
  • they become an Auditor, who can never own an agent.

The agent keeps every grant it holds, but nobody is accountable for it. It is orphaned:

  • the agent list shows Owner left on it, the owner as Former member, and counts orphaned agents in the summary;
  • an agent_authorization.owner_orphaned alert (warning) is raised as soon as the member leaves, and the daily job raises any it missed. The alert is raised once for each owner the agent was orphaned from. It names the agent, never the person;
  • the evidence counts it, and the evidence package’s owner_active column says no.

To resolve it, open the agent and choose Reassign owner, or use Coverage. The new owner must be an active member who is not an Auditor. The agent’s grants and policy stay as they are. Reassigning needs Manage agent authorization and is audited as agent_authorization.owner.reassign with both owners’ user ids. You can also pull the agent’s kill switch.

Coverage lists every AI agent seen in the environment, not only those registered in the gateway:

Seen asWhere it comes fromOwner
Gateway agentAgent access: agents with a gateway tokenThe enrolled owner
Coding agentThe AI inventory: coding tools reported by the collector or by coding-agent tracesThe inventory owner
Agent (traces)The AI inventory: applications sending traces that call toolsThe inventory owner
Microsoft 365 CopilotThe AI inventory: the Microsoft 365 Copilot connectorThe inventory owner

Each agent shows its owner and their state, its permissions, when it was last seen, and its flags:

  • Owner: Active, Owner left, No owner, or Named as text for an inventory owner typed as free text. Shield360 cannot check whether a text owner is still a member, so assign a member instead.
  • Permissions: for a gateway agent, its grants and data authorizations, and whether it is enrolled. Other agents show Not governed by the gateway: Shield360 does not enforce what they can do, so it does not guess.
  • Flags: Unused access from the least-privilege view (idle agents, grants never used, tools never called, grants to every tool), and overdue access reviews.

An administrator can assign an owner from the list. A gateway agent that is not enrolled is enrolled with an owner and a purpose. An agent seen only in the inventory gets a member as owner on its inventory record. This is audited as agent_authorization.owner.assign, with user ids and not names. Only agents seen in the inventory’s lookback period are listed. Retired assets are left out.

If the AI inventory cannot be read, the list shows gateway agents only and says so.

The evidence check Every AI agent has an owner who is still an active member (agents.owned) reads the same list as Coverage. It is:

  • not applicable when no agent is seen,
  • a gap while any agent has no owner or its owner has left. The finding names up to five of them,
  • no evidence when the AI inventory could not be read and only gateway agents were checked,
  • met otherwise. Owners named as text count as owners, and the finding says how many could not be checked.

It backs ISO/IEC 42001 A.3.2 (AI roles and responsibilities), NIST AI RMF GOVERN 1.2 (accountability and governance roles), EU AI Act Art. 26, and OWASP ASI03 (identity and privilege abuse) and ASI10 (rogue agents and lack of oversight).

The evidence check Every AI agent has an owner, a purpose and a current access review (agents.authorized) is:

  • not applicable while no agent holds a live token,
  • a gap while any live agent holds access with no owner and purpose recorded, or a review is more than two weeks late,
  • met otherwise, with the period’s reviews and denied requests as evidence. The finding states that tool and data access is enforced at the gateways, model and spend limits at the AI proxy for agents that send their token, and destination limits are advisory unless a proxy calls the check API.

The period’s inbound decisions (other organisations’ agents checked at your own APIs) count too: the check is applicable once an inbound decision has been recorded, even in an environment with no agents of its own, and the finding gives how many inbound calls were checked and denied.

It backs ISO/IEC 42001 A.3.2 and A.9.2, EU AI Act Art. 14 and Art. 26, and OWASP ASI03. The evidence package carries agent-authorization.json and agent-authorization.csv: every agent’s owner and whether they are still an active member, purpose, risk, grants, limits, last and next review and kill switch, with the period’s reviews, elevations and decision counts.

Auditors read agent authorization through the controls and the evidence package. The Security screens stay closed to them.

Separate from elevation requests, an approval rule makes a person approve a gateway tool call before it runs, every time, even when the agent is granted the tool. A rule names tool patterns (such as github.delete_*), optionally the agents it applies to, the alert channels the approval card goes to (Teams, Slack, email or a webhook), and how long an approval waits (5 minutes to 7 days, default 60 minutes). The first enabled rule that covers the agent and the tool holds the call. How the agent is told, who may approve and how approvers are identified are described in Approvals before risky actions.

Approval rules are managed through the API only; there is no screen for them yet. They belong to the environment of your signed-in session.

Method and pathPermissionDoes
GET /api/agent-access/approval-rulesagent_access.readLists the environment’s rules
POST /api/agent-access/approval-rulesagent_access.writeAdds a rule: { name, toolPatterns, agentIds?, channelIds?, expiresMinutes?, enabled? }
PUT /api/agent-access/approval-rules/<id>agent_access.writeReplaces a rule (same body as POST)
DELETE /api/agent-access/approval-rules/<id>agent_access.deleteRemoves it. Waiting approvals keep their state

An environment holds up to 50 rules. A rule has 1 to 20 tool patterns, up to 50 agents (which must be agents of the environment) and up to 5 channels (which must be your organisation’s alert channels). To require approval only when the arguments meet a condition, such as an amount over a limit, use a Require approval action policy instead.

PermissionLets youShipped roles
View agent authorizationSee agents, their effective permissions, decisions, elevations and reviews, and simulate requestsAdministrator, Compliance officer, Analyst
Manage agent authorizationEnrol agents, edit their policy and grants, assign and reassign owners, and pull the kill switchAdministrator
Attest agent access reviewsReview any agent (an owner may always review their own)Administrator, Compliance officer
Approve agent elevationsDecide elevation requests (never your own)Administrator, Compliance officer

Every route checks these on the server; the page only hides what you cannot do. The read-only demo shows every action disabled.

The Simulate tab answers “what would happen if this agent asked for…?” with the same decision the gateways make, for a tool (service.tool), a table and data classes, a model and cost, or a host, optionally on behalf of a person and in a run context. Nothing is logged. Effective permissions shows the whole matrix at once, optionally as a person. In the decision log, Why? explains a denial, says what would allow it and how the same request is decided now.

Agent authorization is built to take more resource types and identities without changing its model:

  • Resource types: every target is a typed identifier { type, id } with a namespaced action (crm:export). A new resource type registers its own rule with registerResourceType (lib/platform/agent-authorization/decide.ts); an unregistered type is denied.
  • Agent identities: an external workload or agent identity (OIDC, SPIFFE, Entra Agent ID) maps to an agent through registerAgentIdentityResolver (lib/platform/agent-authorization/principal.ts). A resolver authenticates a calling agent. It does not discover agents: Coverage reads those from the gateway and the AI inventory.
  • Spend: every spend decision goes through checkAgentSpend (lib/platform/agent-authorization/spend.ts).
  • Approval channels: onElevationRequested and onElevationDecided tell a channel (a chat approval card) about requests, and decideElevation applies every rule whichever channel decides.