Skip to main content
SecureAuthSecureAuth
← Product Blog

AI Agents Security

Your IdP authorized the connection, not the action

Enterprise-Managed Authorization governs which agents connect to which servers. The spec says the IdP never sees the traffic — so what the agent does once connected is still yours to govern.

Renjith Babu6 min read
On this page

If you’ve turned on Enterprise-Managed Authorization for your AI agents, your identity provider now controls which agents connect to which servers. It does not control what they do once connected — and the spec says so in plain language. This post is about that gap: why connection governance and action authorization are two different decisions, and why the second half is still yours to build.

EMA and Cross App Access are having a moment. Underneath the branding is a genuinely good open standard — worth adopting — and this piece is about the one thing it was never built to do.

The security team turns on Enterprise-Managed Authorization. Agents now provision through the enterprise identity provider on first login. Connections are governed by group and role, revocation is one click, and there is a clean audit trail of which agent reached which server. The dashboard goes green and someone closes the ticket: “agent access is governed now.” That sentence is where the trouble starts — and right now the market is repeating it at volume.

Figure 1 — One governed decision at the identity provider, then every call the agent makes, through no gate at all.

It’s not wrong about what was built. It’s wrong about what “governed” covers. EMA governs the connection. What the agent does once connected runs somewhere the identity provider cannot see, and the specification says so in plain language. Connection and authorization are two different decisions, and for the last few months they’ve been treated as one.

How ID-JAG actually works

Strip the product names off and look at the mechanism, because the mechanism is good and worth understanding on its own terms.

Enterprise-Managed Authorization is an MCP authorization extension that went stable in mid 2026. Underneath it sits a new IETF draft, the Identity Assertion JWT Authorization Grant (ID-JAG), which is itself an extension of OAuth 2.0 Token Exchange (RFC 8693). That is the whole trick: take token exchange, the mechanism your stack already speaks, and add a grant that lets an identity provider assert “this client may act for this user at that server.”

Okta shipped the first implementation and has been loudest about it, so the conversation sounds like it’s about one vendor’s product. It isn’t. ID-JAG is an IETF draft, not a feature anyone owns. Any advanced OAuth provider can implement it, and several will. So the critique that follows is not “one vendor’s product is incomplete.” It’s structural: the connection-layer mechanism, whoever ships it, was scoped to govern connections.

The flow is three standard pieces:

Figure 2 — Org policy runs at exactly one step, the token exchange. Everything after it rides on the access token that step produced.

What you genuinely get is real, regardless of whose logo is on it. No more per-user OAuth consent sprawl, with refresh tokens scattered across laptops. The durable authority lives at the identity provider. The ID-JAG is short-lived, one-time, and bound to a single server’s audience, so it cannot be replayed elsewhere. Revoke a user and the next exchange fails everywhere at once. You get central visibility, central revocation, and central policy over who may connect. It’s the right way to govern the door, and you should adopt it.

Then read the one line in the spec that should stop you from closing the ticket.

“The IdP has no visibility into the MCP traffic”

That is the spec’s own language. Follow what it means.

Org policy runs at exactly one moment: the token exchange, where the provider decides whether this client may reach this server at these scopes. That decision is made once. The ID-JAG it produces is then redeemed for an access token, and that access token typically lives around twenty-four hours, refreshed silently without the user returning to SSO. For the length of that window, every call the agent makes carries a valid bearer token and meets no policy at all.

The decision is frozen at the top by a real standard with real cryptography — trustworthy, but coarse. One decision, made once, covering every call that follows.

Figure 3 — One governed decision at issuance, then a ~24 hour window in which no call meets policy.

What connection governance can’t decide

The mechanism answers a connection question: can this user connect this client to this server, and with which scopes? It never answers the authorization question: should this specific action run, right now, on this resource, in this context? Everything below follows from that one gap.

Scope-level, decided once

The granularity is capped at whatever scopes the server defined, and it’s set once at issuance rather than per call. If a server never split read and write into separate scopes, you cannot express “read yes, delete no.” A support agent granted write scope over customer data can export the whole table or purge records it was never meant to touch, and the connection layer has no place to stop it.

No runtime context

Because the provider never sees the traffic, it cannot reason about the actual request: which resource, what time, how many calls in the last minute, whether this action fits the task the agent was given. Context-aware decisions require seeing the call. This layer does not.

The token is narrower than people assume

The access token from this flow is good for the MCP server only. It is not a credential for the provider’s general REST API, which sits behind its own separate authorization. “We govern the MCP connection” is not “we govern access to the system behind it.”

Adoption is early

The identity provider has to implement the grant and the server has to support it, which is a code change on both sides, not a config flip. Everything outside that set falls back to per-user cached OAuth. The connection problem is solved for the apps that adopted the standard and unsolved for the rest.

Revocation comes with an asterisk

Revoke at the provider and new exchanges stop immediately. An access token already issued keeps working until it expires or the resource server happens to check. The kill switch stops re-issuance now; it does not reach into the twenty-four-hour token already in flight.

Connection governs the front door; the rooms behind it don’t lock.

What “governed” covers, and what it does not:

Figure 4 — The connection layer is settled. The action layer is the half still on your desk.

What’s left to build: runtime, per-call decisions

The boundary is clean once you separate the two decisions. The connection-governance gap is closed. The per-action, runtime decision is the half it leaves open, and that half is still yours to build.

This is the correct division of labor, not a flaw in the standard. Connection governance belongs at the identity provider, and ID-JAG puts it there well. Per-action authorization belongs somewhere else entirely: inline on the call path, where the real request and response actually exist, because that is the only place a context-aware allow, deny, or step-up decision can be made about a specific action.

Which leaves the real question: when the agent makes its four-thousandth call of the day, what in the path can say no?

When the agent makes its four-thousandth call of the day, what can say no?

Connection governance belongs at your identity provider, and ID-JAG puts it there well. The per-action decision has to happen inline, where the real request exists — that is what SecureAuth’s Agent Authority does: allow, deny, or step up on every call, with every decision written down.

By continuing, you agree to our Privacy Policy and Terms, and consent to receive communications.