---
title: Authorizing Gemini agents on behalf of users with Ping Identity solutions
description: Authorize a Gemini agent acting on behalf of a user to call an MCP tool with scoped, short-lived delegation tokens.
component: identity-for-ai
page_id: identity-for-ai:integrations:idai-authorizing-gemini-on-behalf-of-users-with-ping
canonical_url: https://developer.pingidentity.com/identity-for-ai/integrations/idai-authorizing-gemini-on-behalf-of-users-with-ping.html
llms_txt: https://developer.pingidentity.com/identity-for-ai/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: 2026-10-14T20:28:12Z
keywords: ["Identity for AI", "ai identity", "ai security", "Google Cloud Gemini Enterprise", "Gemini Enterprise Agent Platform", "PingOne Authorize", "authentication", "authorization"]
section_ids:
  how-this-works: How this works
  components: Components
  token-chain: Token chain
  benefits-of-this-approach: Benefits of this approach
  goals: Goals
  what-youll-do: What you'll do
  before-you-begin: Before you begin
  tasks: Tasks
  deploy-mcp-server: Deploy the Stripe MCP Server
  create-policies: Create the policies in PingOne Authorize
  deploy-extension-service: Deploy the Agent Gateway Service Extension
  create-gateway: Create the Agent Gateway
  deploy-agent: Deploy the Financial Agent
  deploy-bridge: Deploy the Agent Bridge
  deploy-chat-ui: Deploy the Chat UI
  validation: Validation
  troubleshooting: Troubleshooting
  whats-next: What's next
---

# Authorizing Gemini agents on behalf of users with Ping Identity solutions

This use case secures an agent that calls protected tools and resources on behalf of a human user. The human proves their identity, and that identity is preserved through every delegation boundary between the user, agent, and downstream services. The Agent Gateway Service Extension asks PingOne Authorize for a policy decision and, when approved, mints a scoped, short-lived token that identifies the human user. The extension then forwards the request to the MCP server, which calls downstream resources to execute operations for the human.

This use case builds on the [Integrating Gemini Enterprise Agent Platform with Ping Identity solutions](idai-integrating-gemini-agent-platform-with-ping.html) architecture by adding a human in the loop to the flow. You can find more information about [token exchange with delegation](https://docs.pingidentity.com/pingone/use_cases/p1_oauth_2_token_exchange_delegation.html) in the PingOne documentation.

## How this works

Consider an agent that purchases products on behalf of an authenticated user. The following diagram shows the components involved:

![Diagram showing an AI agent requesting access to a resource with human involvement.](_images/idai-gemini-agent-user-flow.png)

1. The user signs on with PingOne through the Chat UI.

2. The agent exchanges the user's token for a delegated token that names the agent as the actor.

3. The agent runtime routes Model Context Protocol (MCP) requests through the Agent Gateway to the Agent Gateway Service Extension.

4. The Agent Gateway Service Extension validates the delegated token, resolves the user's email, and asks PingOne Authorize whether this agent is permitted to act for this user on this transaction.

5. Upon permit, the Agent Gateway Service Extension performs a second token exchange, minting a token audienced for the Stripe MCP Server that preserves the user's identity and records the full delegation chain. The extension then injects the token and forwards the request.

### Components

| Component                                                                                                                                                                                           | Role                                                                                                                                                       |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Chat UI](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/blob/main/pingone/agent-on-behalf-of-user/services/chat-ui)                                                 | Chat interface that the user signs on to PingOne and interacts with.                                                                                       |
| [Agent](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/blob/main/pingone/agent-on-behalf-of-user/services/agent)                                                     | Financial agent acting as an MCP client. Reads the user token and performs token exchange.                                                                 |
| [Agent Bridge](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/blob/main/pingone/agent-on-behalf-of-user/services/agent-bridge)                                       | Google Cloud entry point. Validates the user token and stores it in the agent session state.                                                               |
| [Agent Gateway](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/blob/main/pingone/agent-on-behalf-of-user/services/agent-gateway)                                     | Google-managed policy enforcement point that forwards agent requests to the Agent Gateway Service Extension over the gRPC remote procedure call framework. |
| [Agent Gateway Service Extension](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/blob/main/pingone/agent-on-behalf-of-user/services/agent-gateway-extension-service) | Handler that sends requests to PingOne Authorize, exchanges the agent's token, and injects the resulting token into the request.                           |
| [Stripe MCP Server](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/blob/main/pingone/agent-on-behalf-of-user/services/stripe-mcp-server)                             | Downstream resource that the agent invokes to make a purchase.                                                                                             |
| [PingOne](https://docs.pingidentity.com/pingone)                                                                                                                                                    | Identity provider (IdP) that issues the agent's token, the delegated agent token, and the delegated tool token.                                            |
| [PingOne Authorize](https://docs.pingidentity.com/pingone/authorization_using_pingone_authorize/p1az_overview.html)                                                                                 | External policy decision point that evaluates authorization requests.                                                                                      |

### Token chain

The token flow begins when the user signs on with PingOne through the Chat UI. The Financial Agent presents the user's token to PingOne as the subject of a token exchange, together with its own client credentials token as the actor. PingOne checks the user token's `may_act` claim against the acting client before minting the delegated token, which still names the user as the subject. The Agent Gateway Service Extension later exchanges that delegated token the same way, minting the final tool token for the Stripe MCP Server. Each exchange adds its actor to the `act` claim, so the final token records the full delegation chain. The agent and Agent Gateway's actor tokens are omitted from this overview for simplicity.

* User token: the Chat UI's token

  ```json
  {
    "iss": "https://auth.pingone.<region>/<env-id>/as",
    "sub": "<alice-user-id>",
    "client_id": "<chat-ui-client-id>",
    "aud": "finance-agent",
    "scope": "openid stripe_mcp:invoke",
    "grant_type": "authorization_code",
    "may_act": { "sub": "<finance-agent-client-id>" }
  }
  ```

  * `sub`: Identifies the human user as the principal subject of the token.

  * `client_id`: Identifies the chat bot as the OAuth client that requested the token.

  * `aud`: Identifies the Financial Agent resource as the recipient of the token.

  * `scope`: Grants the privileges required to invoke the Stripe tools.

  * `may_act`: Authorizes the Financial Agent to delegate next.

* Delegated token: the agent's exchanged token

  ```json
  {
    "iss": "https://auth.pingone.<region>/<env-id>/as",
    "sub": "<alice-user-id>",
    "client_id": "<finance-agent-client-id>",
    "aud": "google-agent-gateway",
    "scope": "stripe_mcp:invoke",
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "act": { "sub": "<finance-agent-client-id>", "act": null },
    "may_act": { "sub": "<agent-gw-extension-client-id>" }
  }
  ```

  * `sub`: Identifies the human user as the principal subject of the token.

  * `client_id`: Identifies the Financial Agent as the OAuth client that requested the token.

  * `aud`: Identifies the Agent Gateway as the recipient of the token.

  * `scope`: Grants the privileges required to invoke the Stripe tools.

  * `act`: Identifies the Financial Agent as the source of delegation.

  * `may_act`: Authorizes only the Agent Gateway Service Extension to delegate next.

* MCP tool token: the Agent Gateway's delegated (exchanged) token

  ```json
  {
    "iss": "https://auth.pingone.<region>/<env-id>/as",
    "sub": "<alice-user-id>",
    "client_id": "<agent-gw-extension-client-id>",
    "aud": "stripe-mcp-server",
    "scope": "stripe_mcp:invoke",
    "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
    "act": {
      "sub": "<agent-gw-extension-client-id>", "act": {
        "sub": "<finance-agent-client-id>", "act": null
      }
    }
  }
  ```

  * `sub`: Identifies the human user as the principal subject of the token. The user's identity is preserved end to end.

  * `client_id`: Identifies the Agent Gateway Service Extension as the OAuth client that requested the token.

  * `aud`: Identifies the Stripe MCP Server as the recipient of the token.

  * `scope`: Grants the privileges required to invoke the Stripe tools.

  * `act`: Identifies the Agent Gateway Service Extension as the source of delegation, on behalf of the agent.

### Benefits of this approach

* **No standing credentials in the agent:** The agent never holds a token that acts directly on a resource. It only receives a delegated token scoped to the Agent Gateway.

* **Compound authorization:** PingOne Authorize evaluates the user and the agent together. A rogue agent can't use a stolen user token, and a user can't call the tool through an unauthorized agent.

* **Delegation proof:** The tool token carries a nested `act` chain naming every actor in order: the Agent Gateway Service Extension and then the agent. PingOne only builds that chain after checking each token's `may_act` claim at exchange time, so the tool can see exactly who acted for whom, end to end.

* **Centralized policy:** PingOne Authorize owns the authorization decision. Policies can be updated centrally without modifying or redeploying the agent, the gateway, or the MCP server.

## Goals

* Demonstrate how to authorize an agent to call a protected tool on behalf of a human user.

* Use PingOne to perform a token exchange that mints a delegated token for a downstream tool.

## What you'll do

1. [Deploy the MCP server](#deploy-mcp-server) to Google Cloud Run and register it in Google Agent Registry.

2. [Create PingOne Authorize policies](#create-policies) that decide whether the Agent Gateway Service Extension permits agent requests to the MCP server.

3. [Deploy the Agent Gateway Service Extension](#deploy-extension-service) to Cloud Run.

4. [Create the Agent Gateway](#create-gateway) and attach the Service Extension to it.

5. [Deploy the agent](#deploy-agent) and create a PingOne resource that licenses the Agent Gateway Service Extension as the only actor allowed to exchange tokens bound for the Agent Gateway.

6. [Deploy the Agent Bridge](#deploy-bridge) to Cloud Run.

7. [Deploy the Chat UI](#deploy-chat-ui) to Cloud Run.

## Before you begin

In addition to meeting the prerequisites in the [integration overview](idai-integrating-gemini-agent-platform-with-ping.html#idai-gemini-prereqs), ensure you have a Stripe account with products and customers configured. Learn more in [Set up your account](https://docs.stripe.com/get-started/account/set-up) in the Stripe documentation.

## Tasks

You can find implementation files and code samples for this use case in the [Agent On-Behalf-Of User](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user) GitHub repository.

### Deploy the Stripe MCP Server

The [Stripe MCP Server](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user/services/stripe-mcp-server) exposes Stripe tools to an agent.

On every request, it:

* Validates the `iss`, `aud`, `scope`, and `signature` claims of the inbound token injected by the Agent Gateway Service Extension.

* Reads the caller's email from the `X-User-Email` header injected by the Agent Gateway Service Extension.

* Executes Stripe operations on behalf of that user.

You'll configure Stripe, deploy the MCP Server to Cloud Run, register it in Agent Registry, and configure a matching resource in PingOne to ensure every token issued for tool access carries claims that prove delegation.

> **Collapse: Configure Stripe**
>
> In the Stripe Dashboard, create the products and customers the agent operates on. Each customer must have a saved payment method attached to their account so that the `create_stripe_payment_intent` tool can charge them without requiring card details at runtime.
>
> |   |                                                                      |
> | - | -------------------------------------------------------------------- |
> |   | The customer email in Stripe must match the user's email in PingOne. |

> **Collapse: Create the MCP server resource in PingOne**
>
> Add a custom resource in PingOne that represents the Stripe MCP Server the agent is allowed to access.
>
> Two grant types are used to request tokens for this resource: the Agent Gateway Service Extension's `client_credentials` grant (which has no subject or actor) and the token exchange grant, where the subject token carries the user's identity. You'll configure three attributes with attribute mappings to ensure each grant yields the correct claims:
>
> * `sub`: Stamps `no-subject` on the `client-credentials` grant. On a token exchange, it carries the subject token's `sub` through, so the user's identity is preserved all the way to the Stripe MCP Server.
>
> * `act`: Stamps `noActor` on the `client-credentials` grant. On a token exchange, `act` is set only if the subject token's `may_act` claim names the exchanging actor. Otherwise it returns `null`, and because `act` is required, a `null` fails the exchange. This enforces the security boundary that only the agent can exchange a user token onto this resource.
>
> |   |                                                                                                                                                                             |
> | - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
> |   | You can find more details about [adding custom resources](https://docs.pingidentity.com/pingone/applications/p1_adding_custom_resources.html) in the PingOne documentation. |
>
> 1. In the PingOne admin console, go to **Applications > Resources** and click the **[icon: plus, set=fa]**icon.
>
> 2. Define the resource:
>
>    1. **Resource Name**: `AOBOU Stripe MCP Server`
>
>    2. **Audience**: `stripe-mcp-server`
>
> 3. Click **Next**.
>
> 4. Define attributes for the resource:
>
>    Detailed steps follow the table.
>
>    | Attribute    | Required | Expression                                                                                                                                                                                                                                                                                                |
>    | ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>    | `sub`        | No       | ```spel
>    (#root.context.requestData.grantType == "client_credentials") ? "no-subject" : #root.context.requestData.subjectToken.sub
>    ```                                                                                                                                                                     |
>    | `act`        | Yes      | ```spel
>    (#root.context.requestData.grantType == "client_credentials")?"noActor":((#root.context.requestData.subjectToken.may_act.sub == #root.context.requestData.actorToken.client_id)?{"sub":#root.context.requestData.actorToken.client_id,"act":#root.context.requestData.subjectToken.act}:null)
>    ``` |
>    | `grant_type` | No       | ```spel
>    #root.context.requestData.grantType
>    ```                                                                                                                                                                                                                                                           |
>
>    1. Click the **Gear** icon ([icon: gear, set=fa]) next to the `sub` attribute, enter the expression, and click **Save**.
>
>       Learn more about expressions in [Using the expression builder](https://docs.pingidentity.com/pingone/pingone_expression_language/p1_use_expression_builder.html) in the PingOne documentation.
>
>    2. Click **+ Add** and name the attribute `act`.
>
>    3. Click [icon: gear, set=fa], enter the expression, and click **Save**.
>
>    4. Select the **Required** checkbox for the `act` attribute.
>
>       This ensures that any token exchange that fails to set `act` is rejected.
>
>    5. Click **+ Add** and name the attribute `grant_type`.
>
>    6. Click [icon: gear, set=fa], enter the expression, and click **Save**.
>
> 5. Click **Next**, then click **+ Add Scope**.
>
> 6. Name the scope `stripe_mcp:invoke`.
>
> 7. Click **Save**.

> **Collapse: Deploy the MCP server to Cloud Run**
>
> Build the MCP server with configured environment variables and deploy it as a Cloud Run service.
>
> 1. Set environment variables for the MCP server:
>
>    1. In the cloned Gemini Enterprise Agent Platform Integrations repository, go to the `pingone/agent-on-behalf-of-user/services/stripe-mcp-server` directory.
>
>    2. Make a copy of the `.env.sample` file and name it `.env`:
>
>       ```bash
>       cp .env.sample .env
>       ```
>
>    3. Set environment variables in the `.env` file:
>
>       | Variable                    | Value                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
>       | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       | `GC_REGION`                 | Your Google Cloud Platform region. For example: `us-central1`.                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
>       | `GC_CLOUD_RUN_SERVICE_NAME` | The Cloud Run service name: `` aobou-stripe-mcp-server` ``.                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
>       | `IDP_ISSUER`                | The PingOne issuer URL: `[.userinput]`https\://auth.pingone.\<region>/\<env-id>/as\`\`.Set the placeholders:- \<region>: The country code top-level domain (ccTLD), such as `.com`, `.eu`, `.asia`. You can find this in your PingOne admin console URL. For example:" `https://console.pingone.com/index.html?env=12345678-1234-1234-1234-123456789012` has a ccTLD of `.com`.
>
>       - \<env-id>: The PingOne environment ID. In the example PingOne admin console URL, the ID is `12345678-1234-1234-1234-123456789012`. |
>       | `STRIPE_SECRET_KEY`         | The Stripe secret key. To find this value, in the Stripe Dashboard, go to **Developers > API keys** and copy the value of the **Secret key** field.                                                                                                                                                                                                                                                                                                                                                                   |
>       | `IDP_REQUIRED_AUDIENCE`     | The expected `aud` claim. This matches the audience you gave the Stripe MCP Server resource in PingOne: `stripe-mcp-server`.                                                                                                                                                                                                                                                                                                                                                                                          |
>       | `IDP_REQUIRED_SCOPE`        | The scope the inbound token must carry to invoke the Stripe MCP Server: `stripe_mcp:invoke`.                                                                                                                                                                                                                                                                                                                                                                                                                          |
>
> 2. In the `pingone/agent-on-behalf-of-user/services/stripe-mcp-server` directory, run the following command:
>
>    ```bash
>    make deploy
>    ```
>
>    This builds the Docker image, pushes it to Google Container Registry, and deploys it to Cloud Run.

> **Collapse: Register the MCP server in Agent Registry**
>
> Register the MCP server in Agent Registry so the Agent Gateway recognizes it as an approved egress destination.
>
> 1. In Google Cloud, go to **Agent Platform > Agents > Govern > Agent Registry** and click **Add MCP Server**.
>
> 2. Enter the following values:
>
>    * **Name**: `AOBOU Stripe MCP Server`
>
>    * **Description**: `Stripe MCP Server for Agent On-Behalf-Of User demo`
>
> 3. Select your **Region**. For example: `us-central1`.
>
> 4. Enter the MCP server URL:
>
>    1. To find the URL, duplicate the browser tab and go to **Cloud Run > Services**. Click the **aobou-stripe-mcp-server service**. Copy the URL at the top of the page. For example: `https://aobou-stripe-mcp-server-909399354423.us-central1.run.app`.
>
>    2. In the Agent Registry, paste the URL in the **MCP server URL** field and then add `/mcp` to the end of the URL.
>
> 5. Enter the MCP specification JSON. This is the tool specification that describes the MCP server's endpoints and expected request and response formats.
>
>    1. In the `pingone/agent-on-behalf-of-user/services/stripe-mcp-server` directory in the cloned repository, copy the contents of the `tool-spec.json` file.
>
>    2. In the Agent Registry, paste the contents of the `tool-spec.json` file in the **JSON** field, then click **Next**.
>
>       |   |                                                                                                                                                                           |
>       | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       |   | Keep `tool-spec.json` in sync with the `mcp.NewTool` definitions in `mcp_tools.go`. If the definitions change, update `tool-spec.json` and re-register in Agent Registry. |
>
> 6. Click **Save** to complete the registration.

> **Collapse: Create a Stripe customers group in PingOne**
>
> 1. In the PingOne admin console, go to **Directory > Groups** and click the **[icon: plus, set=fa]**icon.
>
> 2. In the **Name** field, enter `stripe_customers`, and then click **Save**.
>
> 3. In the **Users** tab, click **Add Individually**.
>
> 4. Select any PingOne users who have a matching customer email in Stripe, and then click **Save**.

### Create the policies in PingOne Authorize

Create the policies that decide whether the Agent Gateway Service Extension permits the agent's request to the MCP Server. You'll create a policy for the agent's identity, one for the user's group membership, and one for the purchase amount.

> **Collapse: Add attributes in the Trust Framework**
>
> Add the following attributes that will be used to make a decision.
>
> | Name            | Type   | Resolver Parameter |
> | --------------- | ------ | ------------------ |
> | Agent Client ID | String | agent_client_id    |
> | User Sub        | String | user_sub           |
> | Tool Name       | String | tool_name          |
> | Amount Cents    | Number | amount_cents       |
>
> 1. In the PingOne admin console, go to **Authorization > Trust Framework**.
>
> 2. On the **Attributes** tab, click the **[icon: plus, set=fa]**icon.
>
> 3. Name the attribute `Agent Client ID`.
>
> 4. In the **Resolvers** section, click **[icon: plus, set=fa]Add Resolver** and keep the default **Request Parameter** resolver.
>
> 5. **Optional:** Name the resolver `agent_client_id` to match the parameter name in the agent's request.
>
> 6. For the Value Settings **Type**, keep the default value of **String**.
>
> 7. Click **Save Changes**.
>
> 8. Repeat the steps above to add the `User Sub`, `Tool Name`, and `Amount Cents` attributes, with the corresponding value settings types and optional resolver parameters.

> **Collapse: Create the AOBOU Agent Gateway Policies policy set**
>
> Add a policy set in PingOne Authorize that contains the policies governing the agent's access to the MCP server.
>
> 1. In the PingOne admin console, go to **Authorization > Policies**.
>
> 2. Click the **[icon: plus, set=fa]**icon and select **Add Policy Set**.
>
> 3. Name the policy set `AOBOU Agent Gateway Policies`.
>
> 4. For the **Combining Algorithm**, select **Unless one decision is deny, the decision will be permit**.
>
> 5. Click **Save changes**.

> **Collapse: Create the Only Permit Delegated Agent policy**
>
> Create a policy that permits only the delegated agent to access the MCP server.
>
> 1. In **Authorization > Policies**, select the **AOBOU Agent Gateway Policies** policy set.
>
> 2. Click the **[icon: plus, set=fa]**icon and select **Add Policy**.
>
> 3. Name the policy `Only Permit Delegated Agent`.
>
> 4. In **Applies When**:
>
>    1. Click **+ Comparison** and select the **Agent Client ID** attribute.
>
>    2. Select the **Does Not Equal** operator.
>
>    3. []()For the value, enter this placeholder: `<FINANCE_AGENT_CLIENT_ID>`.
>
>       Later, you'll replace this with the client ID of the agent you want to permit.
>
> 5. For the **Combining Algorithm**, select **Unless one decision is deny, the decision will be permit**.
>
> 6. Click **+ Add Rule**, then for **Effect**, select **Deny**.
>
> 7. Click **Save changes**.

> **Collapse: Create the Only Permit Users in Stripe Group policy**
>
> Create a policy that permits only users in the `stripe_customers` group to access the MCP server.
>
> 1. In **Authorization > Policies**, select the **AOBOU Agent Gateway Policies** policy set.
>
> 2. Click the **[icon: plus, set=fa]**icon and select **Add Policy**.
>
> 3. Name the policy `Only Allow Stripe Group`.
>
> 4. In **Applies When**:
>
>    1. Click **+ Comparison** and select the **User Sub** attribute.
>
>    2. Select the **Is Not Member Of** operator.
>
>    3. For the value, enter `stripe_customers`.
>
> 5. For the **Combining Algorithm**, select **Unless one decision is deny, the decision will be permit**.
>
> 6. Click **+ Add Rule**, then for **Effect**, select **Deny**.
>
> 7. Click **Save changes**.

> **Collapse: Create the Only Permit Stripe Purchases Below $100 policy**
>
> Create a policy that permits only purchases below $100 (10,000 cents) to access the MCP server.
>
> 1. In **Authorization > Policies**, select the **AOBOU Agent Gateway Policies** policy set.
>
> 2. Click the **[icon: plus, set=fa]**icon and select **Add Policy**.
>
> 3. Name the policy `Only Permit Stripe Purchases Below $100`.
>
> 4. In **Applies When**:
>
>    1. Click **+ Comparison** and select the **Tool Name** attribute.
>
>    2. Select the **Equals** operator.
>
>    3. For the value, enter `create_stripe_payment_intent`.
>
>    4. Click **+ Comparison** and select the **Amount Cents** attribute.
>
>    5. Select the **Greater Than** operator.
>
>    6. For the value, enter `10000`.
>
> 5. For the **Combining Algorithm**, select **Unless one decision is deny, the decision will be permit**.
>
> 6. Click **+ Add Rule**, then for **Effect**, select **Deny**.
>
> 7. Click **Save changes**.

> **Collapse: Publish an authorization policy version**
>
> Publish a policy version to deploy your policies to a decision endpoint and make them available for decision evaluations.
>
> 1. In the PingOne admin console, go to **Authorization > Version History**.
>
> 2. Click the **More Options (⋮)** icon next to the **Latest Version** and select **Publish Version**.
>
> 3. In the **Publish to** list, select a decision endpoint.
>
> 4. For the version **Name**, enter `AOBOU`.
>
> 5. Click **Publish**.
>
>    The version name and the endpoint the version is published to are displayed in **Version History**.
>
> 6. Go to **Authorization > Decision Endpoints** and expand the decision endpoint where you published the policy version. Copy the decision endpoint URL and save it somewhere convenient. You'll need it in the next task when you [deploy the Agent Gateway Service Extension](#authz-dec-endpoint).

### Deploy the Agent Gateway Service Extension

The [Agent Gateway Service Extension](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user/services/agent-gateway-extension-service) is an Envoy `ext_proc` gRPC handler that the Agent Gateway calls to request authorization decisions and perform token exchanges.

You'll deploy the service to Cloud Run to govern requests bound for the Stripe MCP Server. During this flow, the service:

* Validates the agent's delegated token, specifically checking the `iss`, `aud`, and `scope` claims.

* Calls PingOne Authorize on `tools/call` requests to evaluate the agent's identity and the purchase amount. Non-invocation requests (`initialize`, `tools/list`) skip this authorization check.

* Upon a permit decision, performs a token exchange to generate a token restricted to the Stripe MCP Server (`aud`).

* Injects the new credential as an `Authorization: Bearer` header before forwarding the request to the Stripe MCP Server.

> **Collapse: Create a PingOne worker application**
>
> Create a PingOne worker application that the Agent Gateway Service Extension uses to call PingOne Authorize for authorization decisions.
>
> 1. In the PingOne admin console, go to **Applications > Applications**.
>
> 2. Click the **[icon: plus, set=fa]**icon and create the application profile:
>
>    1. Name the application `AOBOU PingOne Authorize Worker App`.
>
>    2. For the **Application Type**, click **Worker**.
>
>    3. Click **Save**.
>
> 3. To enable the application, click the toggle next to the application name in the details panel.
>
> 4. On the **Configuration** tab, click the Pencil icon ([icon: pencil, set=fa]), make sure **Client Credentials** is the **Grant Type**, then click **Cancel**.
>
> 5. On the **Roles** tab, click **Grant Roles**.
>
> 6. Expand the **Environment Admin** and **Identity Data Read Only** roles and select your environment for each.
>
> 7. Click **Save**.

> **Collapse: Create a PingOne application for token exchange**
>
> Create a PingOne application that the Agent Gateway Service Extension uses to perform token exchanges for the MCP server.
>
> 1. In the PingOne admin console, go to **Applications > Applications**.
>
> 2. Click the **[icon: plus, set=fa]**icon and create the application profile:
>
>    1. Name the application `AOBOU Agent Gateway Extension`.
>
>    2. For the **Application Type**, click **OIDC Web App**.
>
>    3. Click **Save**.
>
> 3. To enable the application, click the toggle next to the application name in the details panel.
>
> 4. On the **Configuration** tab, click [icon: pencil, set=fa].
>
>    1. For **Grant Type**, select **Client Credentials** and **Token Exchange**.
>
>    2. Clear the **Code** and **Authorization Code** checkboxes.
>
>    3. Click **Save**
>
> 5. On the **Resources** tab, click [icon: pencil, set=fa], then select the **stripe_mcp:invoke** scope on the AOBOU Stripe MCP Server.
>
>    This scope isn't available yet. Complete this step after you [deploy the Financial Agent](#deploy-agent).
>
> 6. Click **Save**.
>
> 7. On the **Overview** tab, copy the **Client ID** for this application and save it somewhere convenient. You'll need it later when you [create the Agent Gateway resource in PingOne](#create-gateway-resource).

> **Collapse: Deploy the Agent Gateway Service Extension to Cloud Run**
>
> Build the service with configured environment variables and deploy it as a Google Cloud Run service.
>
> 1. Set environment variables for the Agent Gateway Service Extension:
>
>    1. In the cloned repository, go to the `pingone/agent-on-behalf-of-user/services/agent-gateway-extension-service` directory.
>
>    2. Make a copy of the `.env.sample` file and name it `.env`:
>
>       ```bash
>       cp .env.sample .env
>       ```
>
>    3. Set environment variables in the `.env` file:
>
>       | Variable                      | Value                                                                                                                                                                                                                                                            |
>       | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       | `GC_REGION`                   | Your Google Cloud Platform region. For example: `us-central1`.                                                                                                                                                                                                   |
>       | `GC_SERVICE_EXTENSION_NAME`   | The name of the Service Extension resource created when this service is registered: `aobou-agent-gateway-extension`.                                                                                                                                             |
>       | `GC_CLOUD_RUN_SERVICE_NAME`   | The Cloud Run service name: `aobou-agent-gateway-extension-service`.                                                                                                                                                                                             |
>       | `IDP_ISSUER`                  | The AOBOU PingOne Authorize Worker App token endpoint: `https://auth.pingone.<region>/<env-id>/as`. Copy this from the **Connection Details > Issuer ID** field on the **Overview** tab of the AOBOU PingOne Authorize Worker App application in PingOne.        |
>       | `EXCHANGE_CLIENT_ID`          | Token-exchange worker app Client ID.                                                                                                                                                                                                                             |
>       | `EXCHANGE_CLIENT_SECRET`      | Token-exchange worker app Client Secret.                                                                                                                                                                                                                         |
>       | `AUTHZ_CLIENT_ID`             | Authorize worker app Client ID.                                                                                                                                                                                                                                  |
>       | `AUTHZ_CLIENT_SECRET`         | Authorize worker app Client Secret.                                                                                                                                                                                                                              |
>       | []()`AUTHZ_DECISION_ENDPOINT` | The PingOne Authorize decision endpoint URL from when you published the policy version in the previous task.                                                                                                                                                     |
>       | `IDP_REQUIRED_AUDIENCE`       | The expected `aud` on the inbound token from the gateway resource: `google-agent-gateway`.                                                                                                                                                                       |
>       | `IDP_REQUIRED_SCOPE`          | The scope the inbound token must carry to invoke the Stripe MCP Server: `stripe_mcp:invoke`.                                                                                                                                                                     |
>       | `TOOL_URL`                    | The MCP tool's Cloud Run base URL. To find this URL:1) Go to **Cloud Run > Services** and click the `aobou-stripe-mcp-server` service.
>
>       2) Copy the URL at the top of the page (for example `https://aobou-stripe-mcp-server-909399354427.us-central1.run.app`). |
>       | `TOOL_SCOPE`                  | The scope requested on the outbound tool token: `stripe_mcp:invoke`.                                                                                                                                                                                             |
>
> 2. In the `pingone/agent-on-behalf-of-user/services/agent-gateway-extension-service` directory, run the following commands:
>
>    ```bash
>    make deploy
>    ```
>
>    This builds the Docker image, pushes it to Google Container Registry, and deploys it to Cloud Run.
>
>    ```bash
>    make register
>    ```
>
>    This registers your deployed Cloud Run service as an available service extension in Google Cloud. Behind the scenes, it renders the `service-extension.tmpl.yaml` template with the live Cloud Run URL and imports the configuration, preparing the extension for use by the Agent Gateway.

### Create the Agent Gateway

The [Agent Gateway](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user/services/agent-gateway) is a Google-managed resource that acts as the policy enforcement point for all agent egress traffic. It intercepts all outbound traffic bound for downstream tools and routes it to the Agent Gateway Service Extension.

You'll configure the gateway to call the Agent Gateway Service Extension, using [Envoy external processing](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_proc_filter) (`ext_proc`), on every request to the Stripe MCP Server. This includes attaching the Agent Gateway Service Extension to the gateway, registering the egress destinations it can reach, and creating the PingOne resource that licenses the Agent Gateway Service Extension as the only actor allowed to exchange tokens bound for the gateway.

> **Collapse: Configure environment variables**
>
> 1. In the cloned Gemini Enterprise Agent Platform Integrations repository, go to the `pingone/agent-on-behalf-of-user/services/agent-gateway` directory.
>
> 2. Make a copy of the `.env.sample` file and name it `.env`:
>
>    ```bash
>    cp .env.sample .env
>    ```
>
> 3. Check the environment variables in the `.env` file. Most are already defined.
>
>    | Variable                    | Value                                                                                                                                               |
>    | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
>    | `GC_REGION`                 | Your Google Cloud Platform region. For example: `us-central1`.                                                                                      |
>    | `GC_GATEWAY_NAME`           | The Agent Gateway's name. For example: `aobou-agent-gateway`.                                                                                       |
>    | `GC_SERVICE_EXTENSION_NAME` | The deployed Agent Gateway Service Extension name, created when the service extension was registered. For example: `aobou-agent-gateway-extension`. |
>    | `GC_AUTHZ_POLICY_NAME`      | Name of the policy resource this creates. For example: `aobou-authz-policy`.                                                                        |

> **Collapse: Create the Agent Gateway in the Google Cloud Console**
>
> Create the Egress Agent Gateway in the Google Cloud Console.
>
> 1. In Google Cloud, go to **Agent Platform > Agents > Govern > Gateways** and click **Add gateway**.
>
> 2. Enter the following values:
>
>    * **Name**: Name the gateway `aobou-agent-gateway`.
>
>    * **Region**: Your Google Cloud Platform region. For example: `us-central1`.
>
>    * **Deployment mode**: Keep the default **Google-managed**.
>
>    * **Governed Access Path**: Keep the default **Agent-to-Anywhere (egress)**.
>
>    * **Access Authorization**: Select **Enforce policies**.
>
>    * **Policy Model**: Select **Allow Policy**.
>
> 3. Click **Save gateway**.

> **Collapse: Attach the Agent Gateway Service Extension to the Agent Gateway**
>
> To enforce your access policies, you must connect the Agent Gateway Service Extension to the Agent Gateway. The `make attach` command populates `authz-policy.tmpl.yaml` with your project, region, and gateway name, and then imports it with `gcloud`, creating an authorization policy that binds the extension to the gateway as a `CONTENT_AUTHZ` policy scoped to the `/mcp` path.
>
> In the `pingone/agent-on-behalf-of-user/services/agent-gateway` directory, run the following command:
>
> ```bash
> make attach
> ```
>
> |   |                                                                                  |
> | - | -------------------------------------------------------------------------------- |
> |   | You can run `make render` alone to inspect the generated YAML without importing. |
>
> There are now two complementary authorization extensions attached to the Agent Gateway:
>
> | Extension                                | Service role    | Target                      | Description                                                                                                                                                                                                                                                          |
> | ---------------------------------------- | --------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
> | `aobou-agent-gateway-iap-authzextension` | `REQUEST_AUTHZ` | `iap.googleapis.com`        | A Google-managed extension automatically created with the gateway. It enforces the Identity-Aware Proxy (IAP) identity and egress check (`iap.egressor`), which appears on the gateway as the **Auth provider: Google Cloud Identity-Aware Proxy**.                  |
> | `aobou-agent-gateway-extension`          | `CONTENT_AUTHZ` | Cloud Run service extension | The extension created in the previous step. It routes traffic to your Cloud Run host and requests an authorization decision. Upon permit, the extension performs the PingOne token exchange and injects the resulting delegated token in the `Authorization` header. |

> **Collapse: Register egress destinations for the Agent Gateway**
>
> The gateway governs all agent egress, so every host the agent reaches must be a registered destination in Agent Registry. Your environment currently includes the following registered destinations:
>
> * **Stripe MCP Server:** This was registered as an MCP server (rather than a standard endpoint) when you deployed it.
>
>   |   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
>   | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>   |   | The registered URL must match the host URL invoked by the agent exactly. Because IAP resolves egress destinations by host name, any mismatch causes IAP to block the request before it ever reaches the service extension. For example, a failure occurs if the registry holds the stable Cloud Run URL (`…​-<project-number>.<region>.run.app`), but the agent calls a direct revision URL (`…​-<hash>-<region>.a.run.app`). If this happens, you'll see a `DENIED` entry in the gateway logs with no `agentRegistryResource`. |
>
> * **Google APIs:** Endpoints for `aiplatform`, `iamcredentials`, and telemetry (`*.mtls.googleapis.com`) were automatically generated during the gateway deployment to support the runtime's internal egress. Don't modify these endpoints.
>
> You'll register the PingOne host as the final required egress endpoint.
>
> |   |                                                                                                                                                                              |
> | - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
> |   | If you completed xref:integrations:idai-authorizing-gemini-autonomous-agents-with-ping.adoc, you already registered the PingOne host as an endpoint. You can skip this task. |
>
> 1. In Google Cloud, go to **Agent Platform > Agents > Govern > Agent Registry** and click **Add Endpoint**.
>
> 2. Enter the following values:
>
>    * **Name**: `PingOne`.
>
>    * **Region**: Your Google Cloud Platform region. For example: `us-central1`.
>
>    * **Destination URL**: Your PingOne host. For example: `https://auth.pingone.com`.
>
> 3. Click **Save**.

> **Collapse: Create the Agent Gateway resource in PingOne**
>
> Add a custom resource in PingOne that represents the Agent Gateway.
>
> In addition to configuring the `sub`, `act`, and `grant_type` attributes, you'll configure the `may_act` attribute to license the Agent Gateway Service Extension as the next actor on every token minted for this resource. Any other client presenting an exchanged token fails the tool resource's `act` check.
>
> |   |                                                                                                                   |
> | - | ----------------------------------------------------------------------------------------------------------------- |
> |   | Set the `may_act` value to the client ID of the AOBOU Agent Gateway Extension application you created in PingOne. |
>
> 1. In the PingOne admin console, go to **Applications > Resources** and click the **[icon: plus, set=fa]**icon.
>
> 2. Define the resource:
>
>    1. **Resource Name**: `AOBOU Google Cloud Agent Gateway`
>
>    2. **Audience**: `google-agent-gateway`
>
> 3. Click **Next**.
>
> 4. Define attributes for the resource:
>
>    Detailed steps follow the table.
>
>    | Attribute    | Required | Expression                                                                                                                                                                                                                                                                                                |
>    | ------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>    | `sub`        | No       | ```spel
>    (#root.context.requestData.grantType == "client_credentials") ? "no-subject" : #root.context.requestData.subjectToken.sub
>    ```                                                                                                                                                                     |
>    | `act`        | Yes      | ```spel
>    (#root.context.requestData.grantType == "client_credentials")?"noActor":((#root.context.requestData.subjectToken.may_act.sub == #root.context.requestData.actorToken.client_id)?{"sub":#root.context.requestData.actorToken.client_id,"act":#root.context.requestData.subjectToken.act}:null)
>    ``` |
>    | `may_act`    | No       | ```spel
>    {"sub":"<GATEWAY_SERVICE_EXT_CLIENT_ID>"}
>    ```                                                                                                                                                                                                                                                     |
>    | `grant_type` | No       | ```spel
>    #root.context.requestData.grantType
>    ```                                                                                                                                                                                                                                                           |
>
>    1. Click the **Gear** icon ([icon: gear, set=fa]) next to the `sub` attribute, enter the expression, and click **Save**.
>
>       |   |                                                                                                                                                                           |
>       | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       |   | Leave the **Required** checkbox cleared. If marked required, standard `client_credentials` requests are rejected by PingOne before the attribute expression is evaluated. |
>
>       Learn more about expressions in [Using the expression builder](https://docs.pingidentity.com/pingone/pingone_expression_language/p1_use_expression_builder.html) in the PingOne documentation.
>
>    2. Click **+ Add** and name the attribute `act`.
>
>    3. Click [icon: gear, set=fa], enter the expression, and click **Save**.
>
>    4. Select the **Required** checkbox for the `act` attribute.
>
>       This ensures that any token exchange that fails to set `act` is rejected. Unauthorized requests evaluate to null and explicitly fail.
>
>    5. Click **+ Add** and name the attribute `may_act`.
>
>    6. Click [icon: gear, set=fa], enter the expression, replace the `<GATEWAY_SERVICE_EXT_CLIENT_ID>` placeholder with the Agent Gateway Service Extension application's **Client ID** in PingOne that you created in the [previous task](#create-pingone-service-ext-app), and click **Save**.
>
>    7. Repeat the steps to configure the `grant_type` attribute with its respective values.
>
> 5. Click **Next**, then click **+ Add Scope**.
>
> 6. Name the scope `stripe_mcp:invoke`.
>
> 7. Click **Save**.

### Deploy the Financial Agent

The [Financial Agent](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user/services/agent) is an ADK-based agent deployed to the Google Cloud Agent Runtime. Operating as an MCP client, it connects to the Stripe MCP Server to execute the `stripe_mcp:invoke` tool.

You'll create an identity for the agent in PingOne and deploy the agent to the Agent Runtime, binding it to the Agent Gateway.

> **Collapse: Create the Financial Agent in PingOne**
>
> 1. In the PingOne admin console, go to **AI Agents** and click the **[icon: plus, set=fa]**icon.
>
> 2. In the **Name** field, enter `AOBOU Financial Agent`.
>
> 3. Click **Save**.
>
> 4. To enable the application, click the toggle next to the application name in the details panel.
>
> 5. On the **Configuration** tab, click [icon: pencil, set=fa]:
>
>    1. For **Grant Type**, select **Token Exchange** and **Client Credentials**.
>
>    2. Clear the **Code** check box.
>
>    3. Click **Save**.
>
> 6. On the **Resources** tab, click [icon: pencil, set=fa], then select the **stripe_mcp:invoke** scope on the AOBOU Google Cloud Agent Gateway.
>
> 7. Click **Save**.
>
> 8. On the **Overview** tab, copy the **Client ID** for this agent and save it somewhere convenient. You'll need it in the next step when you [create the Financial Agent resource in PingOne](#create-financial-agent-resource).

> **Collapse: Create the Financial Agent resource in PingOne**
>
> Create a custom resource in PingOne to represent the Financial Agent.
>
> This resource mints the Chat UI's sign-on token, the user identity that enters the delegation chain at hop 1. Only the `authorization_code` grant type requests tokens from this resource at login, so you'll just configure the **may_act** attribute.
>
> 1. In the PingOne admin console, go to **Applications > Resources** and click the **[icon: plus, set=fa]**icon.
>
> 2. Define the resource:
>
>    1. **Resource Name**: `AOBOU Financial Agent`
>
>    2. **Audience**: `finance-agent`
>
> 3. Click **Next**.
>
> 4. Define an attribute for the resource:
>
>    | Attribute | Required | Expression                              |
>    | --------- | -------- | --------------------------------------- |
>    | `may_act` | No       | ```spel
>    {"sub":"<AGENT_CLIENT_ID>"}
>    ``` |
>
>    1. Click **+ Add** and name the attribute `may_act`.
>
>    2. Click [icon: gear, set=fa], enter the expression, replace the `<AGENT_CLIENT_ID>` placeholder with the Financial Agent application's **Client ID** in PingOne that you created in the [previous step](#create-financial-agent-pingone-app), and click **Save**.
>
>       Learn more about expressions in [Using the expression builder](https://docs.pingidentity.com/pingone/pingone_expression_language/p1_use_expression_builder.html) in the PingOne documentation.
>
> 5. Click **Next**, then click **+ Add Scope**.
>
> 6. Name the scope `stripe_mcp:invoke`.
>
>    The Financial Agent requests this scope when it exchanges the user's sign-on token during token exchange.
>
> 7. Click **Save**.

> **Collapse: Deploy and register the agent in Agent Registry**
>
> To finish the agent setup, deploy it to the Google Cloud Agent Runtime. This deployment automatically registers the agent in the Agent Registry and routes all of its egress traffic through the Agent Gateway.
>
> 1. Set environment variables for the agent:
>
>    1. In the cloned Gemini Enterprise Agent Platform Integrations repository, go to the `pingone/agent-on-behalf-of-user/services/agent` directory.
>
>    2. Make a copy of the `.env.sample` file and name it `.env`:
>
>       ```bash
>       cp .env.sample .env
>       ```
>
>    3. Set environment variables in the `.env` file:
>
>       | Variable              | Value                                                                                                                                                                                                                                                                                                                             |
>       | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       | `GC_REGION`           | Your Google Cloud Platform region. For example: `us-central1`.                                                                                                                                                                                                                                                                    |
>       | `AGENT_DISPLAY_NAME`  | Display name for the Reasoning Engine: `aobou-financial-agent`.                                                                                                                                                                                                                                                                   |
>       | `IDP_ISSUER`          | The PingOne issuer URL: `https://auth.pingone.<region>/<env-id>/as`.To find this endpoint, go to the AOBOU Financial Agent in PingOne. Copy the **Issuer ID** under **Connection Details** on the **Overview** tab.                                                                                                               |
>       | `GC_AGENT_GATEWAY`    | Display name for the Agent Gateway: `aobou-agent-gateway`.                                                                                                                                                                                                                                                                        |
>       | `GATEWAY_AUDIENCE`    | Audience that the Agent Gateway Service Extension expects: `google-agent-gateway`.                                                                                                                                                                                                                                                |
>       | `AGENT_CLIENT_ID`     | The AOBOU Financial Agent's **Client ID**. This is located above **Connection Details** on the agent's **Overview** tab in PingOne.                                                                                                                                                                                               |
>       | `AGENT_CLIENT_SECRET` | The AOBOU Financial Agent's **Client Secret**. This is located above **Connection Details** on the agent's **Overview** tab.                                                                                                                                                                                                      |
>       | `TOOL_MCP_URL`        | The MCP tool's Cloud Run base URL. To find this URL:1) Go to **Cloud Run > Services** and click the **aobou-stripe-mcp-server** service.
>
>       2) Copy the URL at the top of the page (for example: `https://aobou-stripe-mcp-tool-909399354453.us-central1.run.app`).
>
>       3) Paste the URL in the `.env` file and add `/mcp` at the end. |
>       | `TOOL_SCOPE`          | The scope the agent requests during token exchange to authorize access to the downstream MCP server: `stripe_mcp:invoke`.                                                                                                                                                                                                         |
>
> 2. In the `pingone/agent-on-behalf-of-user/services/agent` directory, run the following command:
>
>    ```bash
>    make deploy
>    ```
>
>    The `deploy.py` script provisions the Reasoning Engine using `identity_type = AGENT_IDENTITY`. The script also binds the engine to the gateway and grants it the `roles/iap.egressor` role on the Agent Registry, authorizing the agent to securely reach all registered downstream endpoints.
>
> 3. Complete the Financial Agent's `AGENT_ENGINE_ID` placeholder in the service extension's `.env` file, then redeploy the service extension.
>
> 4. In PingOne, go to the Agent Gateway Service Extension application and assign the `stripe_mcp:invoke` scope on the Financial Agent.

### Deploy the Agent Bridge

The [Agent Bridge](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user/services/agent-bridge) links the PingOne identity of the Chat UI with the Google Agent Runtime identity of the agent. It receives each chat request, validates the user's PingOne token, creates the agent session, and stores the token in the session state where the agent reads it.

> **Collapse: Deploy the Agent Bridge to Cloud Run**
>
> Build the Agent Bridge with configured environment variables and deploy it as a Google Cloud Run service.
>
> 1. Set environment variables for the Agent Bridge:
>
>    1. In the cloned repository, go to the `pingone/agent-on-behalf-of-user/services/agent-bridge` directory.
>
>    2. Make a copy of the `.env.sample` file and name it `.env`:
>
>       ```bash
>       cp .env.sample .env
>       ```
>
>    3. Set environment variables in the `.env` file:
>
>       | Variable                    | Value                                                                                                                                                                                                                                                      |
>       | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       | `GC_REGION`                 | Your Google Cloud Platform region. For example: `us-central1`.                                                                                                                                                                                             |
>       | `GC_CLOUD_RUN_SERVICE_NAME` | The Cloud Run service name: `aobou-agent-bridge`.                                                                                                                                                                                                          |
>       | `IDP_ISSUER`                | The PingOne issuer URL: `https://auth.pingone.<region>/<env-id>/as`. Copy this from the **Connection Details > Issuer ID** field on the **Overview** tab of the AOBOU Financial Agent configuration in PingOne.                                            |
>       | `IDP_REQUIRED_AUDIENCE`     | The required audience for this resource: `finance-agent`.                                                                                                                                                                                                  |
>       | `CORS_ORIGIN`               | The Chat UI Cloud Run URL. For example: `https://aobou-chat-ui-<project-id>.<region>.run.app`.This is a placeholder. After you deploy the Chat UI in the next task, update this value with the actual URL, then redeploy the Agent Bridge.                 |
>       | `AGENT_ENGINE_ID`           | The Financial Agent's Reasoning Engine ID. To find this ID, go to **Agents > Agent Registry** in Google Agent Platform and copy the value following `reasoningEngines:` in the `aobou-financial-agent`'s **Agent ID**. For example: `6179839738431282994`. |
>
> 2. In the `pingone/agent-on-behalf-of-user/services/agent-bridge` directory, run the following command:
>
>    ```bash
>    make deploy
>    ```
>
>    This builds the Docker image, pushes it to Google Container Registry, and deploys it to Cloud Run.

### Deploy the Chat UI

The [Chat UI](https://github.com/pingidentity/gemini-enterprise-agent-platform-integrations/tree/main/pingone/agent-on-behalf-of-user/services/chat-ui) is a single-page application (SPA) built with React/Vite. End users authenticate with PingOne PKCE and chat with the Financial Agent through the Agent Bridge.

> **Collapse: Create the Chat UI application in PingOne**
>
> 1. In the PingOne admin console, go to **Applications > Applications**.
>
> 2. Click the **[icon: plus, set=fa]**icon and create the application profile:
>
>    1. Name the application `AOBOU Chat UI`.
>
>    2. For the **Application Type**, click **Single-Page**.
>
>    3. Click **Save**.
>
> 3. To enable the application, click the toggle next to the application name in the details panel.
>
> 4. On the **Configuration** tab, click [icon: pencil, set=fa]:
>
>    1. Make sure **Authorization Code** with **S256_REQUIRED** is the **Grant Type**.
>
>    2. In the **Redirect URIs** and **Signoff URLs** fields, enter your Chat UI URL from Cloud Run. For example: `https://aobou-chat-ui-PROJECT_ID.REGION.run.app`.
>
>       These are placeholders. After you [deploy the Chat UI to Cloud Run](#deploy-chat-ui-to-cloud-run) in the next step, update these values with the actual URL.
>
> 5. Click **Save**.
>
> 6. On the **Resources** tab, click [icon: pencil, set=fa], and select `stripe_mcp:invoke` on the AOBOU Financial Agent.
>
> 7. Click **Save**.

> **Collapse: Deploy the Chat UI to Cloud Run**
>
> Configure the environment variables required to deploy the Chat UI and connect it to the Agent Bridge.
>
> 1. Set environment variables for the Chat UI:
>
>    1. In the cloned repository, go to the `pingone/agent-on-behalf-of-user/services/chat-ui` directory.
>
>    2. Make a copy of the `.env.sample` file and name it `.env`:
>
>       ```bash
>       cp .env.sample .env
>       ```
>
>    3. Set environment variables in the `.env` file:
>
>       | Variable                    | Value                                                                                                                                                                                                                                                                                                                                                                                                                       |
>       | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
>       | `GC_REGION`                 | Your Google Cloud Platform region. For example: `us-central1`.                                                                                                                                                                                                                                                                                                                                                              |
>       | `GC_CLOUD_RUN_SERVICE_NAME` | The Cloud Run service name: `aobou-chat-ui`.                                                                                                                                                                                                                                                                                                                                                                                |
>       | `VITE_IDP_ISSUER`           | Your PingOne issuer: `https://auth.pingone.<region>/<env-id>/as`.To find this endpoint, go to the AOBOU Chat UI application in PingOne. Copy the **Issuer ID** under **Connection Details** on the **Overview** tab.                                                                                                                                                                                                        |
>       | `VITE_CLIENT_ID`            | The AOBOU Chat UI application's **Client ID**. This is located above **Connection Details** on the **Overview** tab.                                                                                                                                                                                                                                                                                                        |
>       | `VITE_REDIRECT_URI`         | Your Chat UI Cloud Run URL: `https://aobou-chat-ui-<project-id>.<region>.run.app`.After you deploy the Chat UI to Cloud Run, update this value with the actual URL. To find the URL, go to **Cloud Run > Services** and click the **aobou-chat-ui** service. Copy the URI at the top of the page.	This redirect URI must exactly match the Redirect URIs and Signoff URLs configured in the Chat UI application in PingOne. |
>       | `VITE_AGENT_BRIDGE_URL`     | Your Agent Bridge Cloud Run URL. For example: `https://aobou-agent-bridge-<project-id>.<region>.run.app`.                                                                                                                                                                                                                                                                                                                   |
>       | `VITE_SCOPES`               | Enter `openid profile email stripe_mcp:invoke`.                                                                                                                                                                                                                                                                                                                                                                             |
>
> 2. In the `pingone/agent-on-behalf-of-user/services/chat-ui` directory, run the following command:
>
>    ```bash
>    make deploy
>    ```
>
>    This builds the Vite app, packages it in a Docker image, and deploys it to Cloud Run.
>
> 3. Complete the Chat UI's `CORS_ORIGIN` placeholder in the Agent Bridge's `.env` file, then redeploy the Agent Bridge.
>
> 4. Complete the Chat UI's `VITE_REDIRECT_URI` placeholder in the Chat UI's `.env` file, then redeploy the Chat UI.
>
> 5. In the [Chat UI application in PingOne](#create-chat-ui-app-pingone), enter the deployed `aobou-chat-ui` service's Cloud Run URL in the **Redirect URIs** and **Signoff URLs** placeholders.
>
>    This ensures that the Chat UI can successfully redirect users back to the application after authentication.

## Validation

Use the Chat UI as an end user to make a purchase through Stripe.

1. Go to the Chat UI URL (https\://aobou-chat-ui-\<project-id>.\<region>.run.app) and click **Sign In**.

2. Authenticate as a PingOne user that has a matching email configured in Stripe.

3. Ask the agent to list the products and make a purchase.

4. Confirm the amount and payment method.

The transaction completes and a receipt email is sent.

You can observe the delegation by following the logs of the two Cloud Run services (`aobou-agent-gateway-extension-service` and `aobou-stripe-mcp-server`) while the chat runs. In order, you should see:

```text
# Extension service: every MCP request (initialize, tools/list, tools/call)
# is validated, exchanged, and forwarded with a fresh tool token.
[ExtSvc] request authority="aobou-stripe-mcp-server-...run.app" path="/mcp"
[ExtSvc] aobou-stripe-mcp-server-... /mcp — user=<user-sub> agent=<agent-client-id> email=alice@example.com
[ExtSvc] tool token minted (ttl 59m30s)
[ExtSvc] injecting tool token for aobou-stripe-mcp-server-...run.app

# Extension service: PingOne Authorize is consulted on tools/call only.
[ExtSvc] authorize user=<user-sub> agent=<agent-client-id> tool=create_stripe_payment_intent amount_cents=10000 hour=14
[ExtSvc] PingOne Authorize PERMIT user=<user-sub> agent=<agent-client-id>

# Stripe MCP server: every request's token is verified (signature, issuer,
# audience, scope) before handling. The log shows who the call is for (sub,
# the user throughout), which audience it was minted for (aud), who acted for
# it (act.sub, the extension service - the delegation proof), the granted
# scope, and the resolved caller email.
[SupplyChain] Token verified — sub=<user-sub> aud=[stripe-mcp-server] act.sub=<ext-svc-client-id> scope="stripe_mcp:invoke" caller=alice@example.com

# Stripe MCP server: the purchase itself runs only after the PERMIT above.
[SupplyChain] tool=create_stripe_payment_intent - caller=alice@example.com product_id=prod_... quantity=1 total_price=100.00
[SupplyChain] tool=create_stripe_payment_intent - success: caller=alice@example.com product_id=prod_... quantity=1
```

|   |                                                                                                                                                                                                                                                      |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The `initialize` and `tools/list` requests are the agent and tool negotiating the tool schema. Only the final `tools/call` is routed through PingOne Authorize, which is why the `authorize` line appears once per purchase and not during browsing. |

## Troubleshooting

If you encounter issues while deploying or testing the agent, use the following information to help resolve common problems:

* Chat UI authentication fails

  Verify that the AOBOU Chat UI application in PingOne is configured with the Authorization Code grant type with PKCE. Additionally, check that the configured redirect URI exactly matches the URL of your deployed Cloud Run service.

* Chat UI configuration changes aren't applied after deployment

  If you update a `VITE_*` environment variable (such as `VITE_SCOPES`) but the deployed UI doesn't reflect the change, the Docker build cache probably reused a stale compilation layer. Rebuild and deploy the application using the `--no-cache` flag to force Vite to statically embed the new variables in the JavaScript bundle.

* Financial Agent doesn't receive the user token

  Verify that the Agent Bridge is correctly deployed to Cloud Run and that the Chat UI is successfully sending the token to the bridge payload during the initial chat request.

* Requests are blocked before they reach the service extension

  If the Agent Gateway returns a 403 Forbidden error or logs a `DENIED` message with no `agentRegistryResource`, the request is failing Google Cloud's IAP egress check.

  * Make sure the Reasoning Engine identity has the `roles/iap.egressor` role applied.

  * Verify that the downstream URL registered in Agent Registry exactly matches the host URL the agent is configured to call. IAP resolves egress destinations by host name, and a mismatch causes an immediate denial.

* Order Status Agent or MCP server doesn't receive the delegated token

  Confirm that the Agent Gateway Service Extension is correctly deployed and attached to the Agent Gateway. Check the service extension logs in Cloud Run to verify that it's successfully intercepting the request and performing the RFC 8693 token exchange for the target audience.

  If the Order Status MCP Server fails to receive the delegated token, check that the Agent Gateway Service Extension is correctly reminting the token for the MCP server and that the MCP server is correctly validating the token.

* Token validation or token exchange fails

  Verify that your PingOne resources are configured with the correct custom attributes.

  * Ensure the `may_act` claims are set to the client ID of the next permitted actor in the delegation chain.

  * If a token exchange fails with a 400 error during a `client_credentials` grant, verify that the **Required** checkbox is cleared for the `sub` attribute on the target PingOne resource.

* PingOne Authorize policies aren't enforced

  Make sure the PingOne Authorize decision endpoint URL is correctly configured in your service extension environment variables. In PingOne Authorize **Version History**, verify that your policies are published to the correct version.

* PingOne Authorize denies the agent's request

  * Verify that you replaced the \<FINANCE_AGENT_CLIENT_ID> [placeholder](#idai-gemini-aut-agent-id) in the Only Permit Delegated Agent policy with the client ID of the deployed Finance Agent. If this placeholder isn't updated, the policy can't identify the agent and will reject the request.

  * Review [Recent Decisions](https://docs.pingidentity.com/pingone/authorization_using_pingone_authorize/p1az_recent_decisions.html) in PingOne Authorize to identify which policy condition caused the denial.

    |   |                                                                                                                                                                                                                           |
    | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    |   | Enable **Record recent decisions** on your PingOne Authorize decision endpoint to view full request payloads and step-by-step policy evaluation results. This provides visibility into why a specific request was denied. |

## What's next

Learn how to [authorize Gemini Agent2Agent chains](idai-authorizing-gemini-agent2agent-with-ping.html).

|   |                                                                                                                                                                                                                                                                                     |
| - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | To prepare your environment for agent chaining, clean up the resources you deployed for agents on behalf of users. From the `pingone/agent-on-behalf-of-user` directory, run the `make destroy` command to safely remove the Google Cloud infrastructure specific to this use case. |
