Govern AI agent access with Okta Cross App Access and Amazon Bedrock AgentCore – Part 1

An AI agent that updates a ticket or reads a customer record acts for a person, inside applications that person can reach. Your identity team then has to answer a question that per-app OAuth consent and shared service accounts leave open: which agent might act for which user in which application, and how you stop it. Okta Cross App Access (XAA) answers it in your identity provider (IdP). You register the agent in Okta, an administrator approves the applications it might reach, and Okta evaluates policy each time the agent asks to act for a user. In our tests, after an administrator removed a user’s assignment to the agent, Okta refused the agent’s new requests for that user within about 1 second, and tokens already issued expired within 5 minutes. Amazon Bedrock AgentCore is a platform to build, connect, and optimize agents at scale, with any framework or model. This solution uses two of its capabilities to carry out Okta’s decision on AWS. Amazon Bedrock AgentCore runtime, a capability of Amazon Bedrock AgentCore, validates Okta’s grant. Amazon Bedrock AgentCore Identity, a capability of Amazon Bedrock AgentCore, redeems it for a short-lived access token with credentials your agent code doesn’t see, and keeps that token in its token vault. In our tests, AgentCore Identity added about 0.6 seconds to a request that took about 30 seconds end to end. In this post, the first of two, you build a task agent on AgentCore runtime that acts for signed-in users through XAA and AgentCore Identity. You configure the AgentCore Identity parts it needs, enforce each user’s authority in the tools, and see what we measured: what each check refuses, the practices we settled on, and how fast Okta’s controls take effect. Part 2 then puts the same governance behind Amazon Bedrock AgentCore Gateway, a capability of Amazon Bedrock AgentCore, with Cedar policies, a second agent on Amazon Elastic Kubernetes Service (Amazon EKS), and an audit trail in Amazon CloudWatch. Solution overview Okta is the governance plane: it decides which agent might act for which user, against which resource. AgentCore Identity is the execution plane: it holds the agent’s credentials, turns Okta’s decision into a token the resource accepts, and keeps both identities in that token. In Figure 1, the agent and the two Model Context Protocol (MCP) servers it calls all run on AgentCore runtime. Figure 1: Solution architecture, with numbers matching the steps that follow Each request carries three tokens, and each records a different decision: the ID token says who the user is, the Identity Assertion JWT Authorization Grant (ID-JAG) is Okta’s decision, and the access token is what the resource accepts. One request flows like this: The user signs in to the web front end, a backend for frontend (BFF), with OpenID Connect through the agent’s linked Okta app. For each request, the BFF exchanges the user’s ID token for an ID-JAG at Okta’s org authorization server, authenticated as the agent (RFC 8693 token exchange). Okta checks that the agent is active, that the user is assigned to it, and that an administrator connected it to the target authorization server for the requested scopes. The ID-JAG is single-use and expires in 5 minutes. The BFF invokes the agent on AgentCore runtime with the ID-JAG as its bearer token. The runtime’s JWT authorizer accepts only ID-JAGs that Okta issued to this agent. The runtime gets a workload access token from AgentCore Identity that binds the agent’s workload identity to the user, and passes it to the agent code. This workload access token is an AWS-internal binding token: neither Okta nor the resource sees it, so it isn’t one of the three tokens. The agent asks AgentCore Identity for an access token. AgentCore Identity redeems the ID-JAG at the resource’s Okta custom authorization server with the JWT authorization grant (RFC 7523), authenticated as the agent. Okta returns a 5-minute access token that names both the user and the agent and carries the user’s groups. The agent calls the MCP servers with that token. The task manager checks that a registered agent obtained it, and that the user’s group and scope allow the tool. Figure 2 shows the same request as a sequence, with the check that each party makes. Figure 2: The three-token chain and the check each party makes, with the step 4 workload access token staying inside AWS Prerequisites To follow along, you need the following: Prerequisite What we used An AWS account with access to Amazon Bedrock AgentCore and an Anthropic Claude model in Amazon Bedrock US West (Oregon) An Okta org with Cross App Access for AI agents and API Access Management (custom authorization servers) An Okta Integrator Free Plan org Python, the AWS Command Line Interface (AWS CLI), boto3, the AgentCore CLI, and the AgentCore Python SDK, a capability of Amazon Bedrock AgentCore Python 3.11, AWS CLI version 2, boto3 1.43, AgentCore CLI 0.31.1, and AgentCore Python SDK 1.24.1 AWS Identity and Access Management (IAM) permissions Permission to create AgentCore resources and IAM roles The walkthrough takes about 1 hour. AgentCore charges for what you use. See Amazon Bedrock AgentCore pricing . The base for this solution is the AWS sample 08-okta-xaa-delegation-chain in the AgentCore samples repository on GitHub, and you can build the solution in this post on top of it. Beyond that sample, the snippets and configurations in this post show the pattern conceptually. They aren’t a complete, deployable solution. The code is sample code for non-production use, so work with your security and legal teams to meet your organization’s security, regulatory, and compliance requirements before you deploy it. Register the agent in Okta Okta needs an authorization server for the resource, the agent, a connection between them, and a policy that admits the agent’s grant. Do all of these steps in the Okta Admin Console: registering the agent creates its linked app, so you don’t need an app integration wizard. Create a custom authorization server for the resource application with the audience api://task-manager and the custom scopes xaa:read and xaa:write . Request only the resource’s custom scopes: Okta rejects an ID-JAG request that includes OpenID Connect scopes such as openid or profile ( invalid_scope ), so a request needs at least one custom scope and no OpenID Connect scopes. Add a groups claim to its access tokens, filtered to groups that start with xaa- . This claim carries each user’s authority to the tools. In the Admin Console, go to Directory > AI Agents , choose Register AI agent and then Register manually , optionally assign an owner, and create a linked OpenID Connect app. On Client registration , choose Client secret , generate a secret, and then activate the agent. The agent and the app share one client ID, and that app must sign your users in: an ID token from another app fails the exchange with “the client application is not registered for delegation to this agent.” On the agent’s Resource connections tab, connect it to the authorization server, limited to the scopes it needs, as Figure 3 shows. Add an access policy rule to the custom authorization server that allows the agent’s JWT Bearer grant, with a 5-minute access token lifetime. Without the grant type, the second exchange fails with no_matching_policy , and the lifetime bounds how long a revoked delegation keeps working. Assign the users or groups who might act through the agent. They sign in through the linked app, so give it an app sign-in policy that admits them with the authenticators they’ve enrolled. In our sandbox org, the linked app had its own policy with a rule for the test group. For real users, apply your organization’s policy, including multifactor authentication. Figure 3: The task agent’s resource connection in Okta, limited to the xaa:read and xaa:write scopes Okta’s Cross App Access guide covers the console steps, and the AWS sample 08-okta-xaa-delegation-chain scripts the author