

# 使用傳入身分驗證和傳出身分驗證進行身分驗證和授權
<a name="runtime-oauth"></a>

本節說明如何使用 OAuth 和 JWT 承載符記搭配 [AgentCore Identity](identity.md) 來實作代理程式執行時間的身分驗證和授權。您將了解如何設定 Cognito 使用者集區、為 JWT 身分驗證 （傳入身分驗證） 設定代理程式執行期，以及實作以 OAuth 為基礎的第三方資源存取權 （傳出身分驗證）。

如需完整範例，請參閱 [https://github.com/awslabs/amazon-bedrock-agentcore-samples/](https://github.com/awslabs/amazon-bedrock-agentcore-samples/)。

如需搭配 MCP 伺服器使用 OAuth 的資訊，請參閱在 [ AgentCore 執行期中部署 MCP 伺服器](runtime-mcp.md)。

Amazon Bedrock AgentCore 執行期為託管代理程式提供兩種身分驗證機制：

 **IAM SigV4 身分驗證**   
預設身分驗證和授權機制會自動運作，無需其他組態，類似於其他 AWS APIs。  
 **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:InvokeAgentRuntimeForUser` 動作：，以及現有的`bedrock-agentcore:InvokeAgentRuntime`動作。
 **何時使用此標頭與 JWT 承載字符身分驗證**   
此標頭專為下列使用案例而設計：  
+  **具有客戶受管使用者識別符的企業客戶** — 維護自己的使用者身分字串且需要將其傳遞至 AgentCore Identity 以進行憑證繫結的組織。
+  **開發和快速入門案例** — 尚未提供 IdP 字符，且需要快速路徑來測試使用者範圍憑證流程的建置器。

  對於已設定身分提供者的生產部署，請改用 [JWT 承載字符身分驗證](#oauth-sample-overview)。JWT 路徑 (`GetWorkloadAccessTokenForJWT`) 會驗證字符的發行者、簽章和過期，並提供使用者身分的密碼編譯證明。`X-Amzn-Bedrock-AgentCore-Runtime-User-Id` 標頭路徑不會針對已驗證的最終使用者身分驗證 userId，它依賴呼叫工作負載傳遞正確的值，並在您的 IAM 政策上限制誰可以提供它。

   **X-Amzn-Bedrock-AgentCore-Runtime-User-Id 標頭的安全最佳實務** 
**提示**  
如需所有執行期安全建議的合併檢視，請參閱 [ AgentCore 執行期的安全最佳實務](runtime-security-best-practices.md)。

  由於 AgentCore 會將標頭值視為不透明識別符，而不會針對已驗證的身分進行驗證，因此您必須套用下列控制項來維護安全界限：
+  **限制 IAM 許可** — 只有信任的委託人才能擁有 `bedrock-agentcore:InvokeAgentRuntimeForUser`許可。使用 IAM 資源條件，將此許可範圍限定在特定執行時間資源。請勿透過受管政策或萬用字元資源陳述式廣泛授予。
+  **從已驗證的委託人衍生使用者 ID** — 使用者 ID 值應衍生自已驗證委託人的內容 （例如，IAM 發起人身分或使用者字符宣告），而不是接受任意用戶端提供的值。這可防止已驗證的使用者透過手動指定不同的 來模擬另一個使用者`user-id`。
+  **實作稽核記錄** — 記錄已驗證的 IAM 主體 （來自 SigV4 內容） 與傳遞`user-id`值之間的關係。Use 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 - 必須符合 `^.+/\.well-known/openid-configuration$` OpenID Connect 探索 URLs字串
+ 允許對象 - 將針對 JWT 權杖中的 aud 宣告進行驗證的允許對象清單
+ 允許用戶端 – 允許的用戶端識別符清單，將針對 JWT 權杖中的 client\_id 宣告進行驗證
+ 允許範圍 - 將針對 JWT 權杖中的範圍宣告進行驗證的允許範圍清單。`allowedScopes` 授權欄位將設定為字串清單。
+ 必要的自訂宣告 - 將針對傳入 JWT 權杖中包含的宣告名稱和值進行驗證的必要宣告清單。如需設定授權方的詳細資訊，請參閱[設定傳入 JWT 授權方](inbound-jwt-authorizer.md) 

**注意**  
AgentCore 執行期可以支援以 IAM SigV4 或 JWT Bearer Token 為基礎的傳入身分驗證，但不能同時支援兩者。您可以隨時建立不同版本的 AgentCore 執行期，並針對不同的傳入授權類型進行設定。當您使用 Amazon Bedrock AgentCore 建立執行期時，會自動為使用 AgentCore Identity 服務的執行期建立工作負載身分。

**Topics**
+ [限制對閘道的 IAM (SigV4) 傳入呼叫](#runtime-restrict-iam-gateway)
+ [JWT 傳入授權和 OAuth 傳出存取範例](#oauth-sample-overview)
+ [先決條件](#oauth-prerequisites)
+ [步驟 1：建立您的代理程式專案](#prepare-agent)
+ [步驟 2：設定 AWS Cognito 使用者集區並新增使用者](#setup-cognito)
+ [步驟 3 （選用）：使用 AgentCore Gateway 開啟執行時間](#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>

您可以使用 AgentCore Gateway 預付 AgentCore 執行期，讓閘道成為執行期的單一受管進入點 — 為您提供以政策為基礎的授權、Amazon Bedrock Guardrails、請求和回應攔截器，以及統一的可觀測性，這些都適用於代理程式自己的環境之外。如需完整原理以及如何設定，請參閱[使用 AgentCore Gateway 開啟您的執行時間](runtime-security-best-practices.md#security-bp-front-with-gateway)。

但這只有在呼叫者無法直接繞過閘道到達執行時間時才有用。如果您的執行時間使用預設 IAM (SigV4) 傳入授權，您可以限制對閘道的呼叫，讓流量只能透過它到達執行時間。若要達成此目的，請將資源型政策連接至執行時間，以限制對閘道執行角色的呼叫。閘道會擔任其服務角色來簽署對執行期的請求，因此閘道角色是叫用執行期的委託人。允許該角色，並`Deny`為每個其他主體新增明確 ，以便即使使用寬鬆的身分型政策，其他身分也無法叫用執行時間。如需執行時間的資源型政策詳細資訊，請參閱 [Amazon Bedrock AgentCore 的資源型政策](resource-based-policies.md)。

```
{
    "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`條件新增至**閘道執行角色的**信任政策來鎖定角色，以便只有您的閘道可以擔任該角色。[混淆代理人預防](runtime-security-best-practices.md#security-bp-confused-deputy)指引顯示套用至執行時間執行角色的相同技術；在此處套用相同的模式，但將閘道執行角色和範圍的信任政策設定為`aws:SourceArn`閘道 ARN。

## JWT 傳入授權和 OAuth 傳出存取範例
<a name="oauth-sample-overview"></a>

本指南將逐步引導您使用 JWT 格式的 OAuth 相容存取字符來設定要叫用的代理程式執行期。範例代理程式將使用 AWS Cognito 存取權杖進行授權。稍後，您也將了解代理程式程式碼如何代表使用者擷取 Google 字符，以檢查 Google Drive 並擷取內容。

 **您將學到什麼** 

在本指南中，您將了解如何：
+ 設定 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 代理程式）
+ 提供專案名稱
+ 設定其他選項

這會產生：
+ 具有您所選架構的客服人員程式碼
+  `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 Gateway 開啟執行時間
<a name="runtime-front-with-gateway"></a>

您可以使用 AgentCore Gateway 預付 AgentCore 執行期，讓閘道成為執行期的單一受管進入點 — 為您提供以政策為基礎的授權、Amazon Bedrock Guardrails、請求和回應攔截器，以及統一的可觀測性，這些都適用於代理程式自己的環境之外。如需完整原理以及如何設定，請參閱[使用 AgentCore Gateway 開啟您的執行時間](runtime-security-best-practices.md#security-bp-front-with-gateway)。

如果您想要提前此執行時間，請先[建立閘道](gateway-create.md)，再於下一個步驟部署執行時間。部署之後，您會[將執行時間新增為閘道目標](gateway-target-http-runtime.md)。

為了確保呼叫者無法略過閘道，請將執行時間限制為僅接受來自該閘道的呼叫。您可以在下一個步驟中，使用 作為授權方的一部分來設定此項目 `allowedWorkloadConfiguration`（請參閱 [allowedWorkloadConfiguration：限制對閘道的呼叫](#deploy-agent-allowed-workload))。

## 步驟 4：部署您的代理程式
<a name="deploy-agent"></a>

**重要**  
自 **2025 年 10 月 13 日起，**Amazon Bedrock AgentCore 會將服務連結角色 (SLR) 用於工作負載身分許可，而不需要為新代理程式手動設定 IAM 政策。  
服務連結角色詳細資訊：  
 **名稱:** `AWSServiceRoleForBedrockAgentCoreRuntimeIdentity` 
 **服務主體：** `runtime-identity.bedrock-agentcore.amazonaws.com`
 **目的：**管理工作負載身分存取字符和 OAuth 憑證
確保您用來叫用 AgentCore Control APIs的角色具有建立服務連結角色的許可：  

```
{
    "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-roles.md#identity-service-linked-role)。

現在，您將使用您建立的 Cognito 使用者集區，透過 JWT 授權部署代理程式。您需要建立具有授權方組態的代理程式。下表代表各種授權方組態參數，以及我們如何使用這些參數來驗證傳入的權杖。


| authorizer\_configuration | 已解碼權杖中的宣告 | 備註 | 
| --- | --- | --- | 
| 探索 URL → 發行者 | iss | 探索 URL 應指向發行者 URL。這應該符合解碼字符中的 iss 宣告。 | 
| allowedClients | client\_id | 字符中的 client\_id 應與授權方中指定的其中一個允許用戶端相符 | 
| allowedAudience | aud | 字符中 aud 宣告中的其中一個值應與授權方中指定的其中一個允許對象相符 | 
| allowedWorkloadConfiguration |  `internal`  | 選用。啟動時， 用於僅允許您的 AgentCore Gateway 叫用執行時間。請參閱[限制對閘道的呼叫](#deploy-agent-allowed-workload)。 | 

如果同時提供 client\_id 和 aud，代理程式執行時間授權方會驗證兩者。

### allowedWorkloadConfiguration：限制對閘道的呼叫
<a name="deploy-agent-allowed-workload"></a>

上的 `allowedWorkloadConfiguration` 欄位會`customJWTAuthorizer`限制請求身分鏈中允許叫用執行時間的工作負載。將允許的工作負載設定為您的閘道，讓執行時間僅在其身分鏈包含該閘道時接受請求 — 這是 OAuth (JWT) 執行時間強制流量僅透過您在步驟 3 中設定的閘道到達的方式。

您可以使用下列任一欄位提供允許的工作負載。您可以指定一個或兩者 - 如果請求的身分鏈符合**任一**欄位中的項目，則表示您不需要同時提供兩者。
+  **hostingEnvironments** – 允許其工作負載叫用目標的託管環境清單。每個項目都是具有 的物件`arn`。啟動時，唯一支援的託管環境是 AgentCore Gateway，因此每個`arn`環境都必須是 AgentCore Gateway ARN。
+  **workloadIdentities** – 允許叫用目標的工作負載身分名稱清單。工作負載身分名稱**不是** ARN。這是閘道工作負載身分 ARN 的最終區段，您可以在`GetGateway`回應的 `workloadIdentityDetails` 欄位中找到。例如，如果 `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 Gateway 的呼叫。`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 Gateways。

### 建立和部署代理程式執行時間
<a name="deploy-agent-create-deploy"></a>

準備好您的授權方組態後，建立和部署代理程式執行時間。下列範例示範如何使用 AgentCore CLI 或適用於 Python 的 AWS SDK (Boto3) 執行此操作。請注意來自輸出的代理程式執行期 ARN — 在下一個步驟中，您將需要它來叫用代理程式。

**Example**  
 **設定和部署您的代理程式**   

1. 使用 AgentCore CLI 建立您的代理程式專案：

   ```
   agentcore create
   ```

   出現提示時，請選擇您的架構 （在本教學課程中選擇 Strands 代理程式）。

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 日當天或之後建立的**客服人員，**不需要**此政策，因為許可是由服務連結角色自動處理。  

```
{
    "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}} 取代為您正在使用 AWS 的區域。從步驟 3 開始。

1. 將 {{YOUR\_AGENT\_ARN\_HERE}} 取代為步驟 3 中的實際代理程式執行期 ARN。

1. 執行 指令碼：

   ```
   python invoke_agent.py
   ```

## OAuth 錯誤回應
<a name="oauth-error-responses"></a>

OAuth 設定的代理程式遵循 [RFC 6749 (OAuth 2.0) ](https://datatracker.ietf.org/doc/html/rfc6749)身分驗證標準。缺少身分驗證時，服務會傳回包含 WWW-Authenticate 標頭的 401 未授權回應 （根據 [RFC 7235](https://datatracker.ietf.org/doc/html/rfc7235))，讓用戶端能夠透過 GetRuntimeProtectedResourceMetadata API 探索授權伺服器端點。

### 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` URL 指向受保護的資源中繼資料 (PRM) API。PRM API 可讓用戶端探索哪些授權伺服器可保護此代理程式及其 OAuth 端點 URLs。

**注意**  
您必須先在 Cognito 中預先註冊 OAuth 用戶端 （透過 AWS 主控台或 CLI)，才能在使用探索的端點`client_id`之前取得 。Amazon Cognito 不支援動態用戶端註冊 (RFC 7591)。

## 步驟 6：設定您的代理程式以使用 OAuth 存取工具
<a name="oauth-outbound-access"></a>

在本節中，您將了解如何將代理程式程式碼與 AgentCore 登入資料提供者連線，以便使用 OAuth2 身分驗證安全地存取外部資源。

下列範例示範在 Agent Runtime 中執行的代理程式如何向使用者請求 OAuth 同意，讓他們能夠向 Google 帳戶進行身分驗證，並授權代理程式存取其 Google Drive 內容。

如需設定身分的詳細資訊，請參閱[開始使用 AgentCore Identity](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 清單。回呼 URL 應如下所示：https://bedrock-agentcore.us-east-1.amazonaws.com/identities/oauth2/callback/\*\*\*\*\*\*\*\*-\*\*\*\*-\*\*\*\*-\*\*\*\*-\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

請確定您的調用角色具有存取登入資料提供者的必要許可。

### 步驟 6.2：讓代理程式讀取 Google Drive 內容
<a name="enable-google-drive-access"></a>

建立具有代理程式核心 SDK 註釋的工具，如下列範例所示，以自動啟動三個區段的 OAuth 程序。當您的代理程式叫用此工具時，系統會提示使用者在瀏覽器中開啟授權 URL，並授予代理程式存取其 Google Drive 的同意。

```
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. 代理程式執行期會透過 `bedrock-agentcore:GetWorkloadAccessTokenForJWT` API 交換此權杖與工作負載存取權杖，並透過承載標頭 將其交付至您的代理程式程式碼`WorkloadAccessToken`。

1. 在工具調用期間，您的代理程式會使用此工作負載存取字符來呼叫權杖保存庫 API，`bedrock-agentcore:GetResourceOauth2Token`並產生 3LO 身分驗證 URL。

1. 您的代理程式會將此 URL 傳送至 `on_auth_url`方法中指定的用戶端應用程式。

1. 用戶端應用程式會將此 URL 提供給使用者，該使用者會授予代理程式存取其 Google Drive 的同意。

1. AgentCore Identity 服務會安全地接收和快取 Google 存取權杖，直到過期為止，讓使用者的後續請求能夠使用此權杖，而不需要使用者為每個請求提供同意。

**注意**  
AgentCore Identity Service 使用代理程式工作負載身分和使用者 ID （來自傳入 JWT 權杖，例如 AWS Cognito 權杖） 做為繫結金鑰，將 Google 存取權杖存放在 AgentCore 權杖保存庫中，消除重複的同意請求，直到 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 執行期已驗證權杖簽章。

```
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
```

**注意**  
AgentCore CLI 會建立專案結構和組態檔案。`agentcore/agentcore.json` 根據您的架構選擇，視需要在 中調整代理程式組態。

### 步驟 7.3：叫用您的代理程式
<a name="oauth-propagate-jwt-token-invoke-agent"></a>

 使用 OAuth [叫用](#oauth-invoke-agent)您的代理程式，您應該會在 CloudWatch Logs 的代理程式日誌中看到宣告。

## 疑難排解
<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 指向的發行者 URL 應與字符中的發行者宣告相符。執行下列動作以確認它們相符：
  + 選取您在建立代理程式時在授權方組態中提供的探索 URL，例如： `https://cognito-idp.us-east-1.amazonaws.com/us-east-1_nnnnnnnnn/.well-known/openid-configuration`
    + 檢查發行者 URL - `"issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_12345566"` 。這應該符合字符中的 是宣告值。
+  `client_id` 如果提供，字符中的宣告必須符合其中一個授權方 allowedClients 項目
  + 請注意您在建立代理程式時提供的用戶端 ID
  + 確認這符合解碼字符中的 client\_id 宣告
+  `aud` 字符中的宣告必須符合其中一個授權方`allowedAudience`項目，如果提供的話
  + 請注意您在建立客服人員時提供的對象清單
  + 確認這符合解碼字符中的`aud`宣告
+ 字符的有效時間為幾分鐘 （預設 Amazon Cognito 過期時間為 60 分鐘）。視需要擷取新的字符。