In Half 1, you constructed a process agent on Amazon Bedrock AgentCore, a platform to construct, join, and optimize brokers at scale, with any framework or mannequin. The agent runs on Amazon Bedrock AgentCore runtime, a functionality of Amazon Bedrock AgentCore, and acts for signed-in customers by means of Okta Cross App Entry (XAA). Okta determined which agent would possibly act for which person, and Amazon Bedrock AgentCore Identification, a functionality of Amazon Bedrock AgentCore, redeemed Okta’s grant contained in the agent. That proves the governance mechanism, and it runs on a intentionally small topology: one agent, two Mannequin Context Protocol (MCP) servers, and the authorization verify written into every server.
The mechanism scales. The topology doesn’t. Three issues which are nice for one agent and two instruments turn out to be the work in an enterprise with lots of of brokers and 1000’s of instruments:
| What Half 1 does | Why it stops scaling | What Half 2 does as a substitute |
| The agent holds every MCP server’s runtime ARN and calls it straight | N brokers in opposition to M servers is a wiring matrix, and each new instrument touches each agent that wants it | Brokers attain one Gateway endpoint, and the Gateway holds the goal registry |
| The agent’s position holds the token-exchange permission and reads the supplier’s secret | Each agent that acts for customers will get a credential path to each useful resource it’d attain | The Gateway redeems the grant, and the agent’s position holds no token-exchange or secret permissions |
Every MCP server carries the identical teams verify in its personal code |
The identical rule, copied into 1000’s of servers, drifts and may’t be audited or modified in a single place | One default-deny Cedar coverage set, evaluated on the Gateway earlier than instruments run |
On this submit, you make that change on the Half 1 resolution. Amazon Bedrock AgentCore Gateway, a functionality of Amazon Bedrock AgentCore, turns into the one entrance door and redeems Okta’s grant for every goal. Coverage in Amazon Bedrock AgentCore evaluates Cedar insurance policies that bind every instrument to the agent and the scope Okta delegated. A second agent on Amazon Elastic Kubernetes Service (Amazon EKS) joins underneath its personal Okta id, to indicate that the entrance door doesn’t care the place an agent runs. And Amazon Bedrock AgentCore Observability, a functionality of Amazon Bedrock AgentCore, with Amazon CloudWatch provides you one place to learn each choice, together with Okta’s. We additionally examine XAA with per-user OAuth consent for functions that may’t settle for Okta’s grant.
What modifications from Half 1
The Okta configuration, the AgentCore Identification credential supplier, and the MCP servers from Half 1 keep as they’re. Determine 1 reveals the structure with the additions.
Determine 1: The Half 1 resolution with AgentCore Gateway, Coverage, and Observability, a second agent on Amazon EKS, and the audit path, with numbers matching the steps that comply with
- The person indicators in, and the backend for frontend (BFF) exchanges the ID token for an Identification Assertion JWT Authorization Grant (ID-JAG) issued to the duty agent, agent A, as in Half 1.
- The BFF invokes agent A on AgentCore runtime with the ID-JAG.
- Agent A forwards the ID-JAG to its Gateway because the bearer token of its MCP session. The Gateway’s inbound authorizer accepts solely agent A’s ID-JAGs.
- Coverage in AgentCore evaluates Cedar insurance policies for every instrument itemizing and every instrument name, earlier than the Gateway invokes a goal.
- For calls that Cedar permits, the Gateway has AgentCore Identification redeem the ID-JAG for every goal at Okta’s customized authorization server by means of the Half 1 credential supplier. A name that Cedar denies doesn’t redeem the ID-JAG.
- The MCP server checks the person’s teams and scope, as in Half 1, and data every choice as an
authz.verifyspan. - Each hop emits OpenTelemetry spans to AgentCore Observability, which CloudWatch Transaction Search collects, and Okta streams its System Log to CloudWatch by means of Amazon EventBridge.
The reporting agent, agent B, runs on Amazon EKS and follows the identical path by means of its personal Gateway.
Stipulations
Along with the Half 1 resolution, you want the next:
| Prerequisite | Wanted for |
| eksctl, kubectl, and Docker | The second agent on Amazon EKS |
| Okta Log Streaming | Okta’s System Log in CloudWatch |
| AWS Identification and Entry Administration (IAM) permissions | AgentCore Gateways and coverage engines, Amazon EKS clusters, CloudWatch log teams, and Amazon EventBridge guidelines |
The additions take about 90 minutes. The EKS management aircraft prices $0.10 per hour, plus nodes and the Amazon EKS Auto Mode administration charge, and the AgentCore options cost for what you employ. See Amazon EKS pricing and Amazon Bedrock AgentCore pricing.
As in Half 1, the bottom for this resolution is the AWS pattern 08-okta-xaa-delegation-chain on GitHub, and you may construct the Half 2 additions on prime of it. Past that pattern, the snippets and configurations on this submit present the sample conceptually. They aren’t an entire, deployable resolution. The code is pattern code for non-production use, so work together with your safety and authorized groups to fulfill your group’s safety, regulatory, and compliance necessities earlier than you deploy it.
Create a Gateway that accepts the ID-JAG
The Gateway’s inbound authorizer works just like the runtime authorizer from Half 1. Its issuer is Okta’s org authorization server, its viewers is the customized authorization server, and allowedClients pins it to at least one agent:
Determine 2 reveals the ensuing inbound authorizer.
Determine 2: The Gateway accepts solely ID-JAGs that Okta issued to the agent for the useful resource’s authorization server
Every MCP server turns into a Gateway goal whose outbound authorization makes use of TOKEN_EXCHANGE by means of the Half 1 credential supplier, so the Gateway performs the second trade:
Determine 3 reveals a goal configured this manner.
Three particulars matter right here. First, as in Half 1, the goal’s scopes should equal the ID-JAG’s. Second, give every goal a static instrument schema (listingMode set to DEFAULT with an inline mcpToolSchema), so the instrument names your Cedar insurance policies reference are fastened if you write them. In our assessments, insurance policies that identify instruments additionally couldn’t connect to dynamically listed targets. Third, the Gateway pages instruments/listing by goal, so your shopper should comply with the pagination cursor, or instruments from later targets disappear. AgentCore Identification retains the token from the Gateway’s trade, so one single-use ID-JAG serves each instrument name in a session. In our assessments, it additionally opened a second session inside its 5-minute life.
As a result of a credential supplier authenticates as one Okta agent, give every agent its personal Gateway and supplier. Pattern 08-okta-xaa-delegation-chain takes a unique route, during which a Gateway interceptor performs each exchanges itself.
Connect a Coverage in AgentCore engine to the Gateway in ENFORCE mode, and write permit-only insurance policies. Cedar exposes JWT claims as tags. A coverage that reads a lacking tag errors and is skipped. A skipped allow grants nothing, so default deny holds, however a skipped forbid blocks nothing. Guard every tag with hasTag:
The scope tag holds the ID-JAG’s space-separated scope declare, so the 4 situations match xaa:write solely as an entire entry. A scope reminiscent of xaa:write-admin doesn’t match. An identical coverage, written the identical means, permits the learn instruments with xaa:learn. Test that each coverage is ACTIVE earlier than you connect the engine: an engine whose insurance policies did not create leaves the Gateway denying each name. Cedar binds instruments to the agent and its delegated scope, and the MCP server nonetheless decides every person’s authority from the teams declare, as in Half 1.
Level the agent on the Gateway
Agent A now forwards its inbound ID-JAG to the Gateway as a substitute of calling AgentCore Identification itself:
Take away the Half 1 AgentCore Identification statements from the agent’s execution position. That’s the one change to the position, which now holds no token-exchange or secret permissions, as a result of the Gateway’s position holds the permission to trade tokens. Preserve allowedClients on the runtime’s authorizer.
Run a second agent on Amazon EKS
Our second agent, a reporting agent, runs the identical code on Amazon EKS with its personal Okta registration. Its useful resource connection permits solely xaa:learn, and it has its personal Gateway and credential supplier. EKS Pod Identification provides the pod an IAM position that may invoke fashions and write its personal logs and traces, and nothing else. The AWS Distro for OpenTelemetry (ADOT) SDK exports its traces. The agents-on-eks pattern reveals the Pod Identification setup.
Exterior AgentCore runtime, no authorizer sits in entrance of the pod, so the agent validates the ID-JAG earlier than a mannequin name. It checks the signature, issuer, viewers, token kind oauth-id-jag+jwt, expiry, and that client_id is its personal. In the event you saved the Half 1 agent verify within the MCP servers, add agent B’s shopper ID to REGISTERED_AGENTS. Two settings tripped us up. The EKS Auto Mode general-purpose node pool runs solely amd64, so construct multi-architecture photos. And the AgentCore Python SDK, a functionality of Amazon Bedrock AgentCore, binds to localhost until you set DOCKER_CONTAINER=true.
Hint each choice with AgentCore Observability
The spans on this part are AgentCore Observability, the element in Determine 1 that sits between the brokers and CloudWatch. Runtime, Gateway, Identification, and Coverage emit OpenTelemetry spans for every hop with out code modifications, after you activate Transaction Search and hint supply. Your individual providers add theirs with the AWS Distro for OpenTelemetry (ADOT). CloudWatch Transaction Search collects them, the AgentCore console reads them as agent traces, and Amazon CloudWatch Omni reads the identical spans as traces.default, which is what lets one question put them beside Okta’s occasions.
One instrument name due to this fact produces this chain of spans, every naming the management that decided:
| Span | Emitted by | What it data |
AgentCore.Gateway.InboundAuth |
Gateway | Whether or not the inbound ID-JAG was issued to this agent |
AgentCore.Coverage.AuthorizeAction |
Coverage | The Cedar choice for this instrument |
AgentCore.Identification.GetWorkloadAccessToken |
Identification | Binding the agent’s workload id to the person |
AgentCore.Identification.GetResourceOauth2Token |
Identification | Redeeming the ID-JAG at Okta for a scoped entry token |
AgentCore.Gateway.InvokeTool |
Gateway | The instrument name and its final result |
authz.verify |
The MCP server (ADOT) | The person’s teams, the agent, the choice, and the explanation |
Okta’s System Log is the one document AWS can’t emit, so that you deliver it in. Determine 4 reveals each paths assembly in Omni.
Determine 4: The audit path, the place spans and Okta’s System Log attain CloudWatch and one Omni question joins them
To set it up:
- Activate CloudWatch Transaction Search, activate hint supply for every Gateway (see this pattern script), and add ADOT to the BFF and the MCP servers. The duty supervisor writes every choice, the person, and the agent onto an
authz.verifyspan. - In Okta, add a Log Stream for Amazon EventBridge. Okta delivers every occasion to a companion occasion bus in your account, and a rule writes it to a CloudWatch Logs log group. In our assessments, occasions arrived about 1 second after Okta printed them. Every ID-JAG grant occasion names the agent because the actor, the person as a goal, and the granted scopes and useful resource connection.
- Arrange an Omni house within the account and AWS Area, add the Okta log group to the CloudWatch Dataset integration, and save a view,
view.xaa_authz_decisions, over theauthz.verifyspans.
One question then joins every ID-JAG grant to the choices it led to:
For Alice, the end result reveals Okta granting the duty agent xaa:learn xaa:write for her, then the MCP server denying her create_task 16.7 seconds later and permitting list_tasks after that, as Determine 5 reveals.
Determine 5: The Omni question joins Alice’s ID-JAG grant in Okta’s System Log to the 2 selections it led to
Every request can be one hint, from the BFF by means of the agent, the Gateway’s id and coverage checks, and the MCP server’s choice, as Determine 6 reveals. Omni marks the hint as a fault as a result of the agent’s create_task name returned the denial.
Determine 6: One hint for Alice’s request, from the agent’s instrument name by means of the Gateway’s id and Cedar checks to the MCP server’s deny
Two instrumentation particulars matter. ADOT finds the Area and indicators its exports by means of botocore, so add botocore to providers that lack it. Till we did, our MCP servers exported no spans. And ADOT’s agent mode turns off instrumentation for HTTP shopper libraries reminiscent of requests and urllib3 by default, so set OTEL_PYTHON_DISABLED_INSTRUMENTATIONS in your BFF to override that default with a listing that leaves out the BFF’s HTTP shopper (requests, in ours), or its hint context gained’t attain the agent.
Validate the outcomes
We ran every verify by means of each Gateways with the customers from Half 1. Every session listed the instruments, then referred to as list_tasks, create_task, and an worker lookup:
| Caller and path | Instruments listed | create_task |
Reads |
| Alice, agent A, Gateway A | 6 | Denied by the MCP server: requires xaa-writers |
Allowed |
| Bob, agent A, Gateway A | 6 | Created | Allowed |
| Carol, agent A, Gateway A | 6 | Denied by the MCP server: no teams declare |
Allowed |
| Bob, agent B, Gateway B | 4: Cedar hid the write instruments | Refused by the Gateway: “No coverage applies to the request (denied by default)” | Allowed |
Via the deployed brokers, the outcomes matched: agent A denied Alice and Carol and created Bob’s process, and agent B informed Bob it had no instrument to create duties. The identical person received totally different authority by means of totally different brokers, and Okta determined it.
These requests stopped on the entrance door:
| Request | Response |
| Agent B’s ID-JAG at Gateway A, or agent A’s at Gateway B | HTTP 403, MCP error -32002 insufficient_scope |
| An Okta entry token as a substitute of an ID-JAG | HTTP 403, the identical error |
| No token | HTTP 401, “Lacking Bearer token” |
| Agent A’s ID-JAG despatched to agent B on EKS | Refused in 98 milliseconds, earlier than a mannequin name: “issued to a unique agent” |
The Gateway returns the identical generic error for a improper agent and for the improper token kind, so verify your configuration in opposition to the token’s client_id and aud if you see it.
The Gateway’s id and coverage work is small subsequent to the instrument itself. Medians and ninetieth percentiles from 24 hours of Gateway A spans in Omni:
| Span | p50 | p90 |
Gateway.InboundAuth |
34 ms | 69 ms |
Identification.Authorize |
25 ms | 60 ms |
Identification.GetWorkloadAccessToken |
48 ms | 94 ms |
Identification.GetResourceOauth2Token |
70 ms | 439 ms |
Coverage.AuthorizeAction (Cedar, per name) |
47 ms | 56 ms |
Coverage.PartiallyAuthorizeActions (Cedar, per instrument itemizing) |
65 ms | 75 ms |
Gateway.TargetInvocation (the MCP server on AgentCore runtime) |
5,565 ms | 6,273 ms |
The id and coverage spans for one instrument name sum to about 0.2 seconds at their medians, and the MCP server’s personal authz.verify span took underneath 1 millisecond. Gateway B confirmed the identical sample, with GetResourceOauth2Token at 408 milliseconds on the median.
Cross App Entry or per-user consent
XAA applies the place the goal software’s authorization server accepts an ID-JAG. There, your Okta administrator decides which agent might act for which customers, customers see no consent immediate, and Okta evaluates coverage every time a token is requested. Functions with their very own authorization servers, reminiscent of GitHub, depend on every person’s personal OAuth consent as a substitute. Determine 7 compares the 2, as we measured them.
Determine 7: Cross App Entry in contrast with per-user OAuth consent, with the revocation conduct we measured
We deployed the AWS pattern 07-consent-portal-auth-code-flow-targets beside our stack, with Okta signing customers in to an AgentCore Identification consent portal and a GitHub goal by itself Gateway. Alice related a GitHub check account by means of the portal, and Bob by no means related one. The submit Handle end-user OAuth consent for AI brokers with Amazon Bedrock AgentCore describes this lane in full. Right here’s what we noticed:
| Motion | Subsequent GitHub instrument name |
| Alice consented within the portal | Returned her GitHub id |
| Bob, who by no means consented | MCP error -32042 with an AgentCore authorization URL |
| Alice suspended in Okta, earlier token reused | Nonetheless labored: the Gateway checks the inbound token’s signature and expiry, and that token lived 1 hour |
| Alice suspended, new sign-in | Refused |
| Alice unsuspended | Labored with no new consent |
| Alice’s grant disconnected by means of the consent portal’s API | Not related, then -32042 once more |
The 2 lanes revoke otherwise. In XAA, Okta’s controls cease the subsequent ID-JAG mint, and issued tokens expire inside about 5 minutes. Within the consent lane, Okta controls solely sign-in: the saved grant outlived the suspension and stayed till we disconnected it. Select per goal software, not as soon as for the enterprise.
The place this sample applies
In media and leisure, the fleet arrives shortly. A studio or streaming or video games group has brokers for manufacturing monitoring, title and asset metadata, rights and localization, and viewer or participant help, every sitting in entrance of a unique system with its personal authorization mannequin and its personal auditors. The query isn’t whether or not one agent may be ruled. It’s whether or not the hundredth one is ruled the identical means, and whether or not an administrator can nonetheless reply which brokers attain which programs for which customers.
Nothing right here is restricted to that trade. The agent is an id in your IdP, the goal is an OAuth 2.0 authorization server, and the Gateway is the place authorization is set. Groups in monetary providers, healthcare, and the general public sector put totally different assets behind the identical entrance door and get the identical audit path.
What’s subsequent: observability and evaluations
This submit makes use of AgentCore Observability for one function: to show that every permit and deny traces again to a management. There’s extra in it than that, and it’s a physique of labor in its personal proper. The spans already carry the mannequin and gear latency behind each governance choice, Transaction Search can alert on a spike in denials, and AgentCore evaluations can rating an agent’s conduct in opposition to your individual standards, on-line for dwell site visitors or on demand over a selected set of spans. A later submit takes that up: what to measure on a ruled agent, which evaluators catch an agent that experiences success after a refused instrument name, and learn how to run each with out turning your traces into your largest invoice.
Clear up
To keep away from ongoing prices, delete the Half 2 assets, then comply with the cleanup steps in Half 1:
- Delete the Amazon EKS cluster (
eksctl delete cluster) and its Amazon Elastic Container Registry (Amazon ECR) repository. - Delete the Gateways and their targets, then the Coverage in AgentCore engines, after which agent B’s credential supplier.
- Delete the CloudWatch Omni house and area, the Dataset integration, the Amazon EventBridge rule and companion occasion bus, and the CloudWatch log teams.
- In the event you deployed pattern 07, comply with its cleanup steps.
- Delete the IAM roles and insurance policies you created.
- In Okta, delete the log stream, and deactivate and delete agent B and its linked app.
Conclusion
On this submit, you moved the Half 1 resolution from a topology that fits just a few brokers and instruments to at least one that holds up throughout many. The Gateway turned the one entrance door and redeemed Okta’s grant, so the brokers held no instrument credentials. Cedar insurance policies evaluated by Coverage in AgentCore changed the verify copied into every server. A second agent on Amazon EKS joined underneath its personal Okta id. And AgentCore Observability, with Okta’s System Log beside it in CloudWatch Omni, traced every permit and deny again to the agent, the person, and the management that determined it. The governance mechanism didn’t change, which is the purpose: solely the topology round it did.
To get began, discover the AgentCore samples and Okta’s Cross App Entry documentation. For plain token trade by means of a Gateway, learn Implement on-behalf-of token trade for multi-tenant brokers with Amazon Bedrock AgentCore Gateway.
In regards to the authors


