

# 使用入站身份验证和出站身份验证进行身份验证和授权
<a name="runtime-oauth"></a>

[本节介绍如何使用 OAuth 和带身份的 JWT 不记名令牌为代理运行时实现身份验证和授权。AgentCore ](identity.md)您将学习如何设置 Cognito 用户池、配置代理运行时以进行 JWT 身份验证（入站身份验证）以及如何实现对第三方资源的 OAuth-based 访问（出站身份验证）。

有关完整示例，请参阅[https://github.com/awslabs/amazon-bedrock-agentcore-samples/](https://github.com/awslabs/amazon-bedrock-agentcore-samples/)。

有关在 MCP 服务器上使用 OAuth 的信息，请参阅在运行时[部署 MCP](runtime-mcp.md) 服务器。 AgentCore 

Amazon Bedrock AgentCore 运行时为托管代理提供了两种身份验证机制：

 **IAM Sigv4 身份验证**   
与其他 AWS API 类似，无需额外配置即可自动运行的默认身份验证和授权机制。  
 **X-Amzn-Bedrock-AgentCore-Runtime-User-Id 标题**   
如果您的解决方案要求托管代理代表最终用户检索 OAuth 令牌（使用授权码授权），则可以通过在`X-Amzn-Bedrock-AgentCore-Runtime-User-Id`请求中包含标头来指定用户标识符。此标头在内部使用`GetWorkloadAccessTokenForUserId`路径。  
除了现有操作外， InvokeAgentRuntime 使用调用`X-Amzn-Bedrock-AgentCore-Runtime-User-Id header`将需要一个新的 IAM `bedrock-agentcore:InvokeAgentRuntime` 操作:`bedrock-agentcore:InvokeAgentRuntimeForUser`。
 **何时使用此标头而不是 JWT 持有者令牌身份验证**   
此标题专为以下用例而设计：  
+  **拥有客户管理的用户标识符的企业客户** — 维护自己的用户身份字符串并需要将其传递给 Ident AgentCore ity 进行凭据绑定的组织。
+  **开发和快速入门场景** — 还没有 IdP 令牌可用、需要快速路径来测试用户范围的凭证流程的构建者。

  对于配置了身份提供商的生产部署，请改用 [JWT 不记名令牌身份验证](#oauth-sample-overview)。JWT 路径 (`GetWorkloadAccessTokenForJWT`) 验证令牌的发行者、签名和到期日，提供用户身份的加密证明。标`X-Amzn-Bedrock-AgentCore-Runtime-User-Id`头路径不会根据经过身份验证的最终用户身份验证用户 ID，而是依赖调用工作负载来传递正确的值，并依赖您的 IAM 策略来限制谁可以提供该值。

   ** X-Amzn-Bedrock-AgentCore-Runtime-User-Id 标题安全最佳实践** 
**提示**  
有关所有 Runtime 安全建议的综合视图，请参阅 R [ AgentCore untime 安全最佳实践](runtime-security-best-practices.md)。

  由于 AgentCore 将标头值视为不透明的标识符，而无需根据经过身份验证的身份对其进行验证，因此必须应用以下控制措施来维护安全边界：
+  **限制 IAM 权限** — 只有受信任的委托人才应拥有该`bedrock-agentcore:InvokeAgentRuntimeForUser`权限。使用 IAM 资源条件将此权限范围限定为特定的运行时资源。不要通过托管策略或通配符资源声明进行广泛授权。
+  **从经过身份验证的委托人中**派生 user-id 值应从经过身份验证的委托人的上下文（例如，IAM 调用者身份或用户令牌声明）派生，而不是接受客户端提供的任意值。这样可以防止经过身份验证的用户通过手动指定其他用户来冒充其他用户。`user-id`
+  **实施审计日志 — 记录**经过身份验证的 IAM 委托人（来自 Sigv4 上下文）与传递的`user-id`值之间的关系。 AWS CloudTrail 用于监视包含`runtimeUserId`参数的`InvokeAgentRuntime`呼叫。
+  **在不受信任的上下文中拒绝标头** — 对于不需要用户 ID 委派的运行时，请在 IAM 策略中明确拒绝该`bedrock-agentcore:InvokeAgentRuntimeForUser`操作以防止标头被接受：

  ```
  {
     "Statement": [
        {
           "Sid": "DenyUserIdDelegation",
           "Effect": "Deny",
           "Action": "bedrock-agentcore:InvokeAgentRuntimeForUser",
           "Resource": "arn:aws:bedrock-agentcore:REGION:ACCOUNT_ID:runtime/*"
        }
     ]
  }
  ```

 **JWT 不记名令牌认证**   
通过在代理创建期间提供授权方配置，您可以将代理运行时配置为接受 JWT 持有者令牌。  
此配置包括：  
+ 发现 URL-必须与 OpenID Connect 发现网址`^.+/\.well-known/openid-configuration$`的模式相匹配的字符串
+ 允许的受众-允许的受众列表，这些受众将根据智威汤逊代币中的澳元申领进行验证
+ 允许的客户端-允许的客户端标识符列表，这些标识符将根据 JWT 令牌中的 client\_id 声明进行验证
+ 允许的范围-将根据 JWT 令牌中的范围声明进行验证的允许范围列表。`allowedScopes`授权字段将被配置为字符串列表。
+ 必需的自定义声明-将根据传入的 JWT 令牌中包含的索赔名称和值进行验证的必需声明列表。有关配置授权方的详细信息，请参阅[配置入站 J](inbound-jwt-authorizer.md) WT 授权方 

**注意**  
 AgentCore 运行时可以支持基于 IAM Sigv4 或 JWT 不记名令牌的入站身份验证，但不能同时支持两者。您可以随时创建不同版本的 AgentCore Runtime，并针对不同的入站授权类型进行配置。当您使用 Amazon Bedrock 创建运行时时 AgentCore，将使用身份服务自动为您的运行时创建工作负载身 AgentCore 份。

**Topics**
+ [将 IAM (Sigv4) 入站调用限制到您的网关](#runtime-restrict-iam-gateway)
+ [JWT 入站授权和 OAuth 出站访问示例](#oauth-sample-overview)
+ [先决条件](#oauth-prerequisites)
+ [步骤 1：创建您的代理项目](#prepare-agent)
+ [第 2 步：设置 AWS Cognito 用户池并添加用户](#setup-cognito)
+ [第 3 步（可选）：在运行时前使用 AgentCore 网关](#runtime-front-with-gateway)
+ [步骤 4：部署代理](#deploy-agent)
+ [第 5 步：使用不记名令牌调用您的代理](#oauth-invoke-agent)
+ [OAuth 错误响应](#oauth-error-responses)
+ [步骤 6：将您的代理设置为使用 OAuth 访问工具](#oauth-outbound-access)
+ [步骤 7：（可选）将 JWT 令牌传播到运行时 AgentCore](#oauth-propagate-jwt-token)
+ [问题排查](#troubleshooting)

## 将 IAM (Sigv4) 入站调用限制到您的网关
<a name="runtime-restrict-iam-gateway"></a>

您可以在 Runtime 前面使用 AgentCore 网关，使网关成为 AgentCore 运行时的单一受管控入口点，为您提供基于策略的授权、Amazon Bedrock Guardrails、请求和响应拦截器以及统一的可观察性，所有这些都应用于代理自己的环境之外。有关完整原理以及如何进行设置，请参阅[使用 AgentCore 网关在运行时前面](runtime-security-best-practices.md#security-bp-front-with-gateway)。

但是，只有当调用者无法直接绕过网关到达运行时时，这才有用。如果您的运行时使用默认 IAM (Sigv4) 入站授权，则可以限制对网关的调用，以便流量只能通过网关到达运行时。为此，请将基于资源的策略附加到运行时，该策略将调用限制在网关的执行角色上。网关扮演其服务角色来签署对运行时的请求，因此网关角色是调用运行时的委托人。允许该角色，`Deny`并为所有其他委托人添加一个显式角色，这样即使使用基于身份的宽松策略，其他身份也无法调用运行时。有关基于资源的运行时策略的更多信息，请参阅 [Amazon Bedro Resource-based ck 政策](resource-based-policies.md)。 AgentCore

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowOnlyGatewayRole",
            "Effect": "Allow",
            "Principal": { "AWS": "arn:aws:iam::111122223333:role/MyGatewayExecutionRole" },
            "Action": "bedrock-agentcore:InvokeAgentRuntime",
            "Resource": "arn:aws:bedrock-agentcore:us-west-2:111122223333:runtime/RUNTIME_ID"
        },
        {
            "Sid": "DenyOtherPrincipals",
            "Effect": "Deny",
            "Principal": { "AWS": "*" },
            "Action": "bedrock-agentcore:InvokeAgentRuntime",
            "Resource": "arn:aws:bedrock-agentcore:us-west-2:111122223333:runtime/RUNTIME_ID",
            "Condition": {
                "ArnNotEquals": {
                    "aws:PrincipalArn": "arn:aws:iam::111122223333:role/MyGatewayExecutionRole"
                }
            }
        }
    ]
}
```

**提示**  
显式策略`Deny`始终优先于任何政策`Allow`，包括同一账户中基于身份的政策。键入开`Deny`启`aws:PrincipalArn`可确保只有网关的执行角色才能调用运行时，无论您的账户中还有哪些其他权限。

**重要**  
将运行时间限制在网关的执行角色上，其强度取决于对谁可以担任该角色的控制。任何可以担任网关执行角色的委托人都可以像网关一样调用运行时。通过在**网关执行角色的信任策略中添加`aws:SourceArn`和`aws:SourceAccount`条件来锁定角色**，这样只有您的网关才能担任该角色。C [onfused 副手预防](runtime-security-best-practices.md#security-bp-confused-deputy)指南显示了应用于运行时执行角色的相同技术；在此处应用相同的模式，但要将网关执行角色和范围的信任策略设置`aws:SourceArn`为网关 ARN。

## JWT 入站授权和 OAuth 出站访问示例
<a name="oauth-sample-overview"></a>

本指南将引导您完成设置代理运行时的过程，使其使用符合 OAuth 的访问令牌使用 JWT 格式进行调用。示例代理将使用 AWS Cognito 访问令牌进行授权。稍后，您还将了解代理代码如何代表用户获取 Google 令牌，以查看 Google 云端硬盘并获取内容。

 **你会学到什么** 

在本指南中，您将学习如何：
+ 设置 Cognito 用户池，添加用户，并为该用户获取不记名令牌
+ 设置代理运行时以使用 Cognito 用户池进行授权
+ 设置您的代理代码以代表用户调用工具获取 OAuth 令牌

## 先决条件
<a name="oauth-prerequisites"></a>

开始之前，请确保您已具备以下条件：
+ 具有适当权限的 AWS 账户
+ 对 Python 编程的基本了解
+ 熟悉 Docker 容器（用于高级部署）
+ 成功设置运行时的基本代理
+ 最新的 AWS CLI 并`jq`已安装
+ 对 OAuth 授权的基本了解，主要是 JWT 不记名代币、索赔和各种拨款流程

## 步骤 1：创建您的代理项目
<a name="prepare-agent"></a>

使用`agentcore create`命令使用您选择的框架来设置骨架代理项目：

```
agentcore create
```

该命令将提示您：
+ 选择框架（在本教程中选择 Strands Agents）
+ 提供项目名称
+ 配置其它选项

这会生成：
+ 使用所选框架的代理代码
+  `agentcore/agentcore.json` 配置文件
+  `requirements.txt`有必要的依赖关系

**注意**  
生成的代理代码将作为在以下步骤中实现 OAuth 身份验证的基础。

## 第 2 步：设置 AWS Cognito 用户池并添加用户
<a name="setup-cognito"></a>

要设置 Cognito 用户池并创建用户，您需要使用可自动执行该过程的 shell 脚本。

有关更多信息，请参阅[步骤 2：导入身份和身份验证模块](identity-getting-started-google.md#identity-getting-started-step2)。

<a name="setup-cognito"></a> **设置 Cognito 用户池并创建用户** 
+ 使用以下内容创建名为 `setup_cognito.sh` 的文件：

  ```
  #!/bin/bash
  
  # Create User Pool and capture Pool ID directly
  export POOL_ID=$(aws cognito-idp create-user-pool \
    --pool-name "MyUserPool" \
    --policies '{"PasswordPolicy":{"MinimumLength":8}}' \
    --region $REGION | jq -r '.UserPool.Id')
  
  # Create App Client and capture Client ID directly
  export CLIENT_ID=$(aws cognito-idp create-user-pool-client \
    --user-pool-id $POOL_ID \
    --client-name "MyClient" \
    --no-generate-secret \
    --explicit-auth-flows "ALLOW_USER_PASSWORD_AUTH" "ALLOW_REFRESH_TOKEN_AUTH" \
    --region $REGION | jq -r '.UserPoolClient.ClientId')
  
  # Create User
  aws cognito-idp admin-create-user \
    --user-pool-id $POOL_ID \
    --username $USERNAME \
    --region $REGION \
    --message-action SUPPRESS > /dev/null
  
  # Set Permanent Password
  aws cognito-idp admin-set-user-password \
    --user-pool-id $POOL_ID \
    --username $USERNAME \
    --password $PASSWORD \
    --region $REGION \
    --permanent > /dev/null
  
  # Authenticate User and capture Access Token
  export BEARER_TOKEN=$(aws cognito-idp initiate-auth \
    --client-id "$CLIENT_ID" \
    --auth-flow USER_PASSWORD_AUTH \
    --auth-parameters USERNAME=$USERNAME,PASSWORD=$PASSWORD \
    --region $REGION | jq -r '.AuthenticationResult.AccessToken')
  
  # Output the required values
  echo "Pool id: $POOL_ID"
  echo "Discovery URL: https://cognito-idp.$REGION.amazonaws.com/$POOL_ID/.well-known/openid-configuration"
  echo "Client ID: $CLIENT_ID"
  echo "Bearer Token: $BEARER_TOKEN"
  ```

  打开终端窗口并设置以下环境变量：
  +  {{REGION}}— 您要使用的 AWS 区域
  +  {{USERNAME}}— 新用户的用户名
  +  {{PASSWORD}}— 新用户的密码

    ```
    export REGION=us-east-1 // set your desired Region
    export USERNAME=USER NAME
    export PASSWORD=PASSWORD
    ```

    在终端窗口中，运行脚本：

    ```
    source setup_cognito.sh
    ```

    请注意脚本的输出。在接下来的步骤中，您将需要这些值。

此脚本创建 Cognito 用户池、用户池客户端、添加用户并为用户生成不记名令牌。默认情况下，该令牌的有效期为 60 分钟。

## 第 3 步（可选）：在运行时前使用 AgentCore 网关
<a name="runtime-front-with-gateway"></a>

您可以在 Runtime 前面使用 AgentCore 网关，使网关成为 AgentCore 运行时的单一受管控入口点，为您提供基于策略的授权、Amazon Bedrock Guardrails、请求和响应拦截器以及统一的可观察性，所有这些都应用于代理自己的环境之外。有关完整原理以及如何进行设置，请参阅[使用 AgentCore 网关在运行时前面](runtime-security-best-practices.md#security-bp-front-with-gateway)。

如果要预置此运行时，请立即[创建网关](gateway-create.md)，然后再在下一步中部署运行时。部署后，您需要将[运行时添加为网关目标](gateway-target-http-runtime.md)。

为确保呼叫者无法绕过网关，请将运行时限制为仅接受来自该网关的调用。在下一步中，作为授权方的一部分，您可以使用`allowedWorkloadConfiguration`（参见 allowed [WorkloadConfiguration：限制对网关的调用）进行](#deploy-agent-allowed-workload)配置。

## 步骤 4：部署代理
<a name="deploy-agent"></a>

**重要**  
从 **2025 年 10 月 13 日**起，Amazon Bedrock AgentCore 使用 Service-Linked 角色 (SLR) 来获得工作负载身份权限，而不是要求为新代理手动配置 IAM 策略。  
 Service-Linked 角色详情：  
 **名称**：`AWSServiceRoleForBedrockAgentCoreRuntimeIdentity`
 **服务负责人：**`runtime-identity.bedrock-agentcore.amazonaws.com`
 **用途：**管理工作负载身份访问令牌和 OAuth 凭证
确保用于调用 Cont AgentCore rol API 的角色有权创建该 Service-Linked 角色：  

```
{
    "Sid": "CreateBedrockAgentCoreIdentityServiceLinkedRolePermissions",
    "Effect": "Allow",
    "Action": "iam:CreateServiceLinkedRole",
    "Resource": "arn:aws:iam::*:role/aws-service-role/runtime-identity.bedrock-agentcore.amazonaws.com/AWSServiceRoleForBedrockAgentCoreRuntimeIdentity",
    "Condition": {
        "StringEquals": {
            "iam:AWSServiceName": "runtime-identity.bedrock-agentcore.amazonaws.com"
        }
    }
}
```
 **好处**：该 Service-Linked 角色自动提供工作负载身份访问所需的权限，无需手动配置策略。  
有关服务相关角色的详细信息，请参阅[身份服务相关](service-linked-roles.md#identity-service-linked-role)角色。

现在，您将使用您创建的 Cognito 用户池通过 JWT 授权部署代理。您将需要使用授权方配置创建代理。下表列出了各种授权方配置参数以及我们如何使用它们来验证传入的令牌。


| 授权者配置 | 在解码后的令牌中声明 | 注意 | 
| --- | --- | --- | 
| 发现网址 → 发行人 | iss | 发现网址应指向发行者网址。这应该与解码后的令牌中的 iss 声明相匹配。 | 
| 允许的客户 | client\_id | 令牌中的 client\_id 应与授权方中指定的允许客户端之一匹配 | 
| 允许的受众 | aud | 代币中澳元索赔中的一个值应与授权者中指定的允许受众群体之一相匹配 | 
| 允许 WorkloadConfiguration |  `internal`  | 可选。启动时，用于仅允许您的 AgentCore 网关调用运行时。请参见[限制对您的网关的调用](#deploy-agent-allowed-workload)。 | 

如果同时提供了 client\_id 和 aud，则代理运行时授权者将验证两者。

### 允许WorkloadConfiguration：限制对您的网关的调用
<a name="deploy-agent-allowed-workload"></a>

上的`allowedWorkloadConfiguration`字段`customJWTAuthorizer`限制允许请求的身份链中的哪些工作负载调用运行时。为您的网关设置允许的工作负载，以便运行时仅在其身份链包含该网关时才接受请求——这就是 OAuth (JWT) 运行时强制流量只能通过您在步骤 3 中设置的网关到达的方式。

您可以使用以下任一字段提供允许的工作负载。您可以指定一个或两个 — 如果请求的身份链与**任**一字段中的条目相匹配，则该请求将被接受，因此您无需同时提供这两个字段。
+  **Hosting** Environments — 允许其工作负载调用目标的托管环境的列表。每个条目都是一个带有`arn`. 启动时，唯一支持的托管环境是 AgentCore 网关，因此每个托管环境都`arn`必须是 AgentCore 网关 ARN。
+  **workloadIdentitie** s — 允许调用目标的工作负载身份名称列表。工作负载身份名称**不**是 ARN。这是网关工作负载身份 ARN 的最后一部分，你可以在响应`workloadIdentityDetails`字段中找到。`GetGateway`例如，如果`workloadIdentityDetails.workloadIdentityArn`是`arn:aws:bedrock-agentcore:us-east-1:111122223333:workload-identity-directory/default/workload-identity/my-gateway-workload-identity`，则工作负载标识名称为`my-gateway-workload-identity`。

以下示例创建了一个代理运行时，该运行时通过其 ARN 限制对特定 AgentCore 网关的调用。`hostingEnvironments`单独指定是允许网关的最简单方法：

```
{
    "authorizerConfiguration": {
        "customJWTAuthorizer": {
            "discoveryUrl": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_example/.well-known/openid-configuration",
            "allowedClients": ["your-client-id"],
            "allowedWorkloadConfiguration": {
                "hostingEnvironments": [
                    {
                        "arn": "arn:aws:bedrock-agentcore:us-east-1:111122223333:gateway/my-gateway-id"
                    }
                ]
            }
        }
    }
}
```

或者，您可以通过网关的工作负载标识名称来标识网关，或者同时指定两个字段。当两者都存在时，如果请求与任一字段中的条目相匹配，则允许该请求。以下`allowedWorkloadConfiguration`代码段允许使用两个不同的网关，一个由其 ARN 标识，另一个由其工作负载标识名称标识：

```
"allowedWorkloadConfiguration": {
    "hostingEnvironments": [
        {
            "arn": "arn:aws:bedrock-agentcore:us-east-1:111122223333:gateway/my-gateway-1-id"
        }
    ],
    "workloadIdentities": [
        "my-gateway-2-workload-identity"
    ]
}
```

**注意**  
启动时，`allowedWorkloadConfiguration`仅支持 AgentCore 运行时目标，允许的工作负载为 AgentCore 网关。

### 创建和部署代理运行时
<a name="deploy-agent-create-deploy"></a>

授权方配置准备就绪后，创建并部署代理运行时。以下示例展示了如何 AgentCore 使用 CLI 或适用于 Python 的 AWS SDK (Boto3) 来执行此操作。记下输出中的代理运行时 ARN，在下一步中你需要它来调用代理。

**Example**  
 **配置和部署您的代理**   

1. 使用 AgentCore CLI 创建您的代理项目：

   ```
   agentcore create
   ```

   出现提示时，选择您的框架（在本教程中选择 Strands Agents）。

1. 部署您的代理：

   ```
   agentcore deploy
   ```

1. 记下输出中的代理运行时 ARN。下一步你需要这个。
**提示**  
您也可以运行不带标志的`agentcore create`命令，以获得完全交互的体验，指导您完成项目设置。

1. 

   ```
   import boto3
   
   # Create the client
   client = boto3.client('bedrock-agentcore-control', region_name="us-east-1")
   
   # Call the CreateAgentRuntime operation
   response = client.create_agent_runtime(
       agentRuntimeName='HelloAgent',
       agentRuntimeArtifact={
           'containerConfiguration': {
               'containerUri': '111122223333.dkr.ecr.us-east-1.amazonaws.com/my-agent:latest'
           }
       },
       authorizerConfiguration={
           "customJWTAuthorizer": {
               "discoveryUrl": 'COGNITO_DISCOVERY_URL',
               "allowedClients": ['COGNITO_CLIENT_ID']
           }
       },
       networkConfiguration={"networkMode":"PUBLIC"},
       roleArn='arn:aws:iam::111122223333:role/AgentRuntimeRole',
       lifecycleConfiguration={
           'idleRuntimeSessionTimeout': 300,  # 5 min, configurable
           'maxLifetime': 1800                # 30 minutes, configurable
       },
   )
   ```

## 第 5 步：使用不记名令牌调用您的代理
<a name="oauth-invoke-agent"></a>

现在，您的代理已通过 JWT 授权部署，您可以使用不记名令牌调用它。

**注意**  
如果您在[步骤 3](#runtime-front-with-gateway) 中使用网关在运行时前置网关，请在调用之前将已部署的运行时添加为网关目标（参见[AgentCore 运行时目标](gateway-target-http-runtime.md)），然后通过以下示例中显示的网关终端节点而不是运行时终端节点进行调用。

**重要**  
 **对现有用户很重要**：**2025 年 10 月 13 日之前**创建的代理将继续使用代理执行角色来获得身份权限，并**要求**将上述策略附加到代理的执行角色。  
 **新代理**：对于**在 2025 年 10 月 13 日当天或之后**创建的代理，**不需要**此政策，因为权限由 Service-Linked 角色自动处理。  

```
{
    "Sid": "GetAgentAccessToken",
    "Effect": "Allow",
    "Action": [
        "bedrock-agentcore:GetWorkloadAccessToken",
        "bedrock-agentcore:GetWorkloadAccessTokenForJWT",
        "bedrock-agentcore:GetWorkloadAccessTokenForUserId"
    ],
    # point to the workload identity for the runtime; the workload identity can be found in
    # the GetAgentRuntime response and has your agent name in it.
    "Resource": [
        "arn:aws:bedrock-agentcore:region:account-id:workload-identity-directory/default",
        "arn:aws:bedrock-agentcore:region:account-id:workload-identity-directory/default/workload-identity/agentname-*"
    ]
}
```

 **调用代理** 

为您使用 Amazon Cognito 创建的用户获取不记名令牌。

```
# use the password and other details used when you created the cognito user

export TOKEN=$(aws cognito-idp initiate-auth \
    --client-id "$CLIENT_ID" \
    --auth-flow USER_PASSWORD_AUTH \
    --auth-parameters USERNAME='testuser',PASSWORD='PASSWORD' \
    --region us-east-1 | jq -r '.AuthenticationResult.AccessToken')
```

按照以下说明继续调用代理。

使用 OAuth 调用代理。

**Example**  

1. 

   ```
   // Invoke with OAuth token
   export PAYLOAD='{"prompt": "hello what is 1+1?"}'
   
   export BEDROCK_AGENT_CORE_ENDPOINT_URL="https://bedrock-agentcore.us-east-1.amazonaws.com"
   # If you fronted the runtime with a gateway (Step 3), the core endpoint URL is now your gateway URL
   # export BEDROCK_AGENT_CORE_ENDPOINT_URL="https://${GATEWAY_ID}.gateway.bedrock-agentcore.us-east-1.amazonaws.com/${TARGET_NAME}"
   
   export INVOKE_URL="${BEDROCK_AGENT_CORE_ENDPOINT_URL}/runtimes/${ESCAPED_AGENT_ARN}/invocations?qualifier=DEFAULT"
   # If you fronted the runtime with a gateway (Step 3), the preceding URL works but there is also a simpler alternative:
   # export INVOKE_URL="${BEDROCK_AGENT_CORE_ENDPOINT_URL}/invocations"
   
   curl -v -X POST "${INVOKE_URL}" \
   -H "Authorization: Bearer ${TOKEN}" \
   -H "X-Amzn-Trace-Id: your-trace-id" \
   -H "Content-Type: application/json" \
   -H "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id: your-session-id" \
   -d ${PAYLOAD}
   ```

1. 由于 boto3 不支持使用不记名令牌进行调用，因此你需要使用 HTTP 客户端，比如 Python 中的请求库。

   <a name="invoke-agent"></a> **使用不记名令牌调用您的代理** 

1. 使用以下内容创建名为 `invoke_agent.py` Python 脚本：

   ```
   import requests
   import urllib.parse
   import json
   import os
   
   # Configuration Constants
   REGION_NAME = "AWS_REGION"
   
   # === Agent Invocation Demo ===
   invoke_agent_arn = "YOUR_AGENT_ARN_HERE"
   auth_token = os.environ.get('TOKEN')
   print(f"Using Agent ARN from environment: {invoke_agent_arn}")
   
   # URL encode the agent ARN
   escaped_agent_arn = urllib.parse.quote(invoke_agent_arn, safe='')
   
   # Construct the URL — invoke the runtime directly
   url = f"https://bedrock-agentcore.{REGION_NAME}.amazonaws.com/runtimes/{escaped_agent_arn}/invocations?qualifier=DEFAULT"
   
   # If you are fronting the runtime with a gateway (see Step 3), invoke through
   # the gateway target instead (replace GATEWAY_ID and my-target):
   # url = f"https://GATEWAY_ID.gateway.bedrock-agentcore.{REGION_NAME}.amazonaws.com/my-target/invocations"
   
   # Set up headers
   headers = {
       "Authorization": f"Bearer {auth_token}",
       "X-Amzn-Trace-Id": "your-trace-id",
       "Content-Type": "application/json",
       "X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": "testsession123"
   }
   
   # Enable verbose logging for requests
   import logging
   logging.basicConfig(level=logging.DEBUG)
   logging.getLogger("urllib3.connectionpool").setLevel(logging.DEBUG)
   
   invoke_response = requests.post(
       url,
       headers=headers,
       data=json.dumps({"prompt": "Hello what is 1+1?"})
   )
   
   # Print response in a safe manner
   print(f"Status Code: {invoke_response.status_code}")
   print(f"Response Headers: {dict(invoke_response.headers)}")
   
   # Handle response based on status code
   if invoke_response.status_code == 200:
       response_data = invoke_response.json()
       print("Response JSON:")
       print(json.dumps(response_data, indent=2))
   elif invoke_response.status_code >= 400:
       print(f"Error Response ({invoke_response.status_code}):")
       error_data = invoke_response.json()
       print(json.dumps(error_data, indent=2))
   
   else:
       print(f"Unexpected status code: {invoke_response.status_code}")
       print("Response text:")
       print(invoke_response.text[:500])
   ```

1. {{AWS\_REGION}}替换为步骤 3 中您正在使用的 AWS 区域。

1. {{YOUR\_AGENT\_ARN\_HERE}}用步骤 3 中的实际代理运行时 ARN 替换。

1. 运行脚本：

   ```
   python invoke_agent.py
   ```

## OAuth 错误响应
<a name="oauth-error-responses"></a>

OAuth-configured 代理遵守 [RFC 6749 (OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc6749)) 身份验证标准。当缺少身份验证时，该服务会返回带有 WWW-Authenticate 标头的 401 未经授权的响应（根据 [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235)），使客户端能够通过 API 发现授权服务器端点。 GetRuntimeProtectedResourceMetadata 

### 401 未授权-缺少身份验证
<a name="oauth-401-missing-authentication"></a>

如果授权标头中未提供持有者令牌，则响应为：

```
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{ESCAPED_ARN}/invocations/.well-known/oauth-protected-resource?qualifier={QUALIFIER}"
```

 WWW-Authenticate 标题中的`resource_metadata`网址指向受保护资源元数据 (PRM) API。PRM API 使客户端能够发现哪些授权服务器保护此代理及其 OAuth 端点 URL。

**注意**  
在使用发现的端点之前，您必须在 Cognito 中预先注册 OAuth 客户端（通过控制台 AWS 或 CLI）`client_id`才能获取。Amazon Cognito 不支持动态客户端注册 (RFC 7591)。

## 步骤 6：将您的代理设置为使用 OAuth 访问工具
<a name="oauth-outbound-access"></a>

在本节中，您将学习如何使用OAuth2身份验证将代理代码与 AgentCore 凭证提供程序连接以安全访问外部资源。

以下示例演示了在代理运行时中运行的代理如何请求用户同意 OAuth，从而使他们能够使用自己的 Google 帐号进行身份验证并授权代理访问他们的 Google 云端硬盘内容。

有关设置身份的更多信息，请参阅[ AgentCore 身份入门](identity-getting-started.md)。

### 步骤 6.1：设置凭证提供商
<a name="setup-credential-providers"></a>

要设置 Google 凭据提供商，您需要：

1. 向 Google 注册您的应用程序以获取客户端 ID 和客户端密钥

1. 使用 CLI 创建 OAuth 凭证提供商。 AWS 将{{your-client-id}}和{{your-client-secret}}替换为您实际的 Google OAuth2 客户端 ID 和客户端密钥：

   ```
   OAUTH2_CREDENTIAL_PROVIDER_RESPONSE=$(aws bedrock-agentcore-control create-oauth2-credential-provider \
     --name "google-provider" \
     --credential-provider-vendor "GoogleOauth2" \
     --oauth2-provider-config-input '{
         "googleOauth2ProviderConfig": {
           "clientId": "your-client-id",
           "clientSecret": "your-client-secret"
         }
       }' \
   --output json)
   
   OAUTH2_CALLBACK_URL=$(echo $OAUTH2_CREDENTIAL_PROVIDER_RESPONSE | jq -r '.callbackUrl')
   
   echo "OAuth2 Callback URL: $OAUTH2_CALLBACK_URL"
   ```
**注意**  
`callbackUrl`从[CreateOauth2CredentialProvider](https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_CreateOauth2CredentialProvider.html)响应中获取，然后将 URI 添加到您的 Google 应用的重定向 URI 列表中。回传网址应如下所示：https://bedrock-agentcore.us-east-1.amazonaws.com/identities/oauth2/callback/\*\*\*\*\*\*\*\*-\*\*\*\*-\*\*\*\*-\*\*\*\*\*\*-\*\*\*\*\*\*\*\*\*\*\*\*

确保您的调用角色具有访问凭证提供程序所需的权限。

### 步骤 6.2：启用代理程序读取 Google 云端硬盘内容
<a name="enable-google-drive-access"></a>

创建带有代理核心 SDK 注释的工具，如以下示例所示，以自动启动三足式 OAuth 流程。当您的代理调用此工具时，系统会提示用户在浏览器中打开授权网址，并同意代理访问他们的 Google 云端硬盘。

```
import asyncio
from bedrock_agentcore.identity.auth import requires_access_token, requires_api_key

# This annotation helps agent developer to obtain access tokens from external applications
@requires_access_token(
    provider_name="google-provider",
    scopes=["https://www.googleapis.com/auth/drive.metadata.readonly"], # Google OAuth2 scopes
    auth_flow="USER_FEDERATION", # 3LO flow
    on_auth_url=lambda x: print("Copy and paste this authorization url to your browser: ", x), # prints authorization URL to console
    force_authentication=True,
    callback_url='insert_oauth2_callback_url_for_session_binding'
)
async def read_from_google_drive(*, access_token: str):
    print(access_token) #You can see the access_token
    # Make API calls...
    main(access_token)

asyncio.run(read_from_google_drive(access_token=""))
```

**注意**  
有关处理[会话绑定的](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/oauth2-authorization-url-session-binding.html)本地回调服务器实现示例，请参阅 [https://github.com/awslabs/amazon-bedrock-agentcore-samples/blob/main/01-tutorials/03-AgentCore-identity/05-Outbound_Auth_3lo/oauth2_callback_server.py](https://github.com/awslabs/amazon-bedrock-agentcore-samples/blob/main/01-tutorials/03-AgentCore-identity/05-Outbound_Auth_3lo/oauth2_callback_server.py) 

 **幕后会发生什么** 

当这段代码运行时，会发生以下过程：

1. 代理运行时根据配置的授权方对入站令牌进行授权。

1. Agent Runtime 通过 `bedrock-agentcore:GetWorkloadAccessTokenForJWT` API 将此令牌交换为工作负载访问令牌，并通过有效载荷标头将其传送到您的代理代码`WorkloadAccessToken`。

1. 在工具调用期间，您的代理使用此工作负载访问令牌来调用令牌库 API `bedrock-agentcore:GetResourceOauth2Token` 并生成 3LO 身份验证 URL。

1. 您的代理将此 URL 发送到`on_auth_url`方法中指定的客户端应用程序。

1. 客户端应用会将此网址提供给用户，用户同意代理访问他们的 Google 云端硬盘。

1. AgentCore 身份服务可以安全地接收并缓存 Google 访问令牌，直至其过期，从而使用户的后续请求无需用户对每个请求都表示同意，即可使用此令牌。

**注意**  
AgentCore 身份服务使用代理工作负载身份和用户 ID（来自入站 JWT AgentCore 令牌，例如 Cogn AWS ito 令牌）作为绑定密钥，将 Google 访问令牌存储在令牌库中，从而消除在 Google 令牌到期之前重复的同意请求。

## 步骤 7：（可选）将 JWT 令牌传播到运行时 AgentCore
<a name="oauth-propagate-jwt-token"></a>

或者，您可以将授权标头传递给 AgentCore 运行时以提取声明。这可以通过使用请求标头白名单配置来完成。有关更多信息，请参阅 [RequestHeaderConfiguration](https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_RequestHeaderConfiguration.html)。

### 步骤 7.1：修改代理代码以读取标题
<a name="oauth-propagate-jwt-token-modify-code"></a>

在此步骤中，您将对代理代码进行更改，以便可以使用 PyJWT 库对 JWT 令牌进行解码和提取声明。

 **requirements.txt** 

将 PyJWT 依赖项添加到生成的`requirements.txt`项目中的文件中。

```
PyJWT
```

 **更新您的代理代码** 

修改生成的项目中的主代理文件（通常`src/main.py`或类似文件，具体取决于您的框架选择），如以下代码所示。您可以在此处跳过验证令牌签名，因为在完成入站授权时， AgentCore Runtime 已经对其进行了验证。

```
import jwt
import json
....

@app.entrypoint
def invoke(payload, context):
    auth_header = context.request_headers.get('Authorization')
    if not auth_header:
        return None

    # Remove "Bearer " prefix if present
    token = auth_header.replace('Bearer ', '') if auth_header.startswith('Bearer ') else auth_header
    try:
        # Skip signature validation as agent runtime has validated the token already.
        claims = jwt.decode(token, options={"verify_signature": False})
        app.logger.info("Claims: %s", json.dumps(claims))
    except jwt.InvalidTokenError as e:
        app.logger.exception("Invalid JWT token: %s", e)

    .....
```

### 步骤 7.2：使用请求标头许可名单创建代理
<a name="oauth-propagate-jwt-token-create-agent"></a>

使用 AgentCore CLI 为代理配置请求标头允许名单。导航到你生成的项目目录并运行：

```
agentcore create --name HelloAgent --framework Strands --model-provider Bedrock --memory none

# Now deploy the agent runtime
agentcore deploy
```

**注意**  
C AgentCore LI 创建项目结构和配置文件。根据需要调整您的框架选择中的`agentcore/agentcore.json`代理配置。

### 步骤 7.3：调用您的代理
<a name="oauth-propagate-jwt-token-invoke-agent"></a>

 使用 OAuth [调用](#oauth-invoke-agent)您的代理，您应该会在日志中的代理日志中 CloudWatch 看到声明。

## 问题排查
<a name="troubleshooting"></a>

### 如何调试与令牌相关的问题
<a name="debug-token-issues"></a>

如果您遇到令牌身份验证问题，可以对令牌进行解码以检查其内容：

```
echo "$TOKEN" | cut -d '.' -f2 | tr '_-' '/+' | awk '{ l=4 - length($0)%4; if (l<4) printf "%s", $0; for (i=0; i<l; i++) printf "="; print "" }' | base64 -D | jq
```

这将输出令牌的有效载荷，如下所示：

```
{
    "sub": "subid",
    "iss": "https://cognito-idp.us-east-1.amazonaws.com/userpoolid",
    "client_id": "clientid",
    "origin_jti": "originjti",
    "event_id": "eventid",
    "token_use": "access",
    "scope": "aws.cognito.signin.user.admin",
    "auth_time": 1752275688,
    "exp": 1752279288,
    "iat": 1752275688,
    "jti": "jti",
    "username": "username"
}
```

对令牌问题进行故障排除时，请检查以下内容：
+ 代理授权方中发现网址指向的发行者网址应与令牌中的发行人声明相匹配。执行以下操作以确认它们匹配：
  + 选择您在创建代理时在授权方配置中提供的发现 URL，例如：`https://cognito-idp.us-east-1.amazonaws.com/us-east-1_nnnnnnnnn/.well-known/openid-configuration`
    + 查看发卡机构网址-`"issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_12345566"`。这应该与令牌中的 iss 索赔值相匹配。
+  `client_id`令牌中的声明必须与授权方 allowedClients 条目之一（如果提供）匹配
  + 记下您在创建代理时提供的客户端 ID
  + 确认这与解码后的令牌中的 client\_id 声明相符
+  `aud`令牌中的声明必须与授权方`allowedAudience`条目之一（如果提供）匹配
  + 请注意您在创建代理时提供的受众列表
  + 确认这与解码后的`aud`令牌中的声明相符
+ 令牌仅在几分钟内有效（Amazon Cognito 的默认有效期为 60 分钟）。根据需要获取新代币。