コンテンツにスキップ

第7章 外部認証を制御する「アイデンティティ」 — 学習メモ

書籍「Amazon Bedrock AgentCore実践入門」第7章のサンプルコード(このフォルダ)を読み解いた個人学習メモ。 AgentCore 全体像は ../../lectures/agentcore_basics/STUDY_NOTES.md 参照。 実行検証は伴わない。コードに現れた API 名だけ断定し、読めない挙動は「〜と推測」で明示する。

一言で

アイデンティティ = エージェントのツールが外部 SaaS(Atlassian 等)の API を呼ぶときの「OAuth 3LO(three-legged OAuth)フローの面倒な部分」を @requires_access_token デコレータ1個に丸ごと肩代わりさせる仕組み。認可URL発行・ユーザー同意・コールバック受信・トークン交換という4段階を、ツール本体のコードから切り離せる。

全体像

このフォルダは2つの独立したプロセスから成る。

  • 01_outbound.py: ツール本体。@requires_access_token で包んだ関数が Atlassian の API を呼ぶ
  • 02_callback_server.py: OAuth の認可完了後のリダイレクトを受け取り、トークン交換を完了させる FastAPI サーバー(http://localhost:9090

両方を同時に起動しておく必要がある(README)。処理の流れは以下(デコレータ内部の詳細な実装はSDK側にあり、コードから直接読めない部分は「推測」と明示する)。

sequenceDiagram
    participant U as ユーザー
    participant Ag as Strandsエージェント(01_outbound.py)
    participant Dec as requires_access_tokenデコレータ
    participant Atl as Atlassian(OAuth認可サーバー)
    participant CB as コールバックサーバー(02_callback_server.py)

    U->>Ag: Atlassianのサイト一覧を取得して
    Ag->>Dec: get_confluence_sites → call_api() を呼ぶ
    Dec->>Dec: 認可URLを発行(on_auth_url)
    Dec-->>U: 認可URLをprintで表示
    U->>Atl: ブラウザで認可URLを開き同意
    Atl-->>CB: callback_url(localhost:9090/oauth2/callback)へリダイレクト
    CB->>Atl: complete_resource_token_auth(session_uri, user_identifier)
    Atl-->>CB: トークン交換完了
    Dec->>Dec: access_tokenをcall_apiへ注入
    Dec->>Atl: Bearerトークン付きでAPI呼び出し
    Atl-->>Dec: レスポンス(JSON)
    Dec-->>Ag: 結果を返す
    Ag-->>U: 最終応答
  • 「Dec→Dec: 認可URLを発行」以降、コールバックサーバーがトークン交換を完了させてから call_apiaccess_token が注入されるまでの間、デコレータ内部がどう待ち合わせている(ポーリングか、セッション ID をキーにした待機か)かはコードから直接読めない。ここは SDK(bedrock-agentcore)内部の実装なので「〜と推測」の扱いとする。

使用ライブラリ・原理

  • bedrock_agentcore.identity.requires_access_tokenbedrock-agentcore==1.6.4): OAuth トークン取得をデコレータで肩代わりする AgentCore Identity の SDK
  • bedrock_agentcore.services.identity.IdentityClient / UserIdIdentifier: コールバック側でトークン交換を確定させるクライアント
  • strands.Agent / @toolstrands-agents==1.38.0): エージェント本体とツール化デコレータ
  • httpx: ツール内部から Atlassian API を叩く HTTP クライアント
  • fastapi + uvicorn: コールバックサーバーの実装

ファイル別の役割

ファイル 役割
01_outbound.py ツール実装。@requires_access_token で包んだ関数が OAuth トークンを使って Atlassian API を呼ぶ
02_callback_server.py OAuth 認可完了後のリダイレクトを受け取り、complete_resource_token_auth でトークン交換を完了させる FastAPI サーバー
pyproject.toml 依存関係の固定(strands-agents==1.38.0, bedrock-agentcore==1.6.4 等、requires-python >= 3.14

中心コードの読み解き

01_outbound.py

@requires_access_token(
    provider_name="AtlassianProvider",
    scopes=["read:confluence-content.all"],
    auth_flow="USER_FEDERATION",
    on_auth_url=lambda url: print(url),
    callback_url="http://localhost:9090/oauth2/callback",
)
def call_api(access_token: str = ""):
    response = httpx.get(
        "https://api.atlassian.com/oauth/token/accessible-resources",
        headers={"Authorization": f"Bearer {access_token}"},
    )
    return response.json()
やってること なぜ
01_outbound.py:10-16 @requires_access_tokencall_api を包む OAuth 3LO のトークン取得処理をデコレータに委譲し、ツール本体は API 呼び出しに専念できる
01_outbound.py:11 provider_name="AtlassianProvider" 事前にマネコン等で登録した OAuth プロバイダー設定を名前で参照するキー。コードだけでは動かず、書籍本文の手順で先に登録が必要(README)
01_outbound.py:13 auth_flow="USER_FEDERATION" ユーザー単位で認可させる 3LO(three-legged OAuth)モードの指定
01_outbound.py:14 on_auth_url=lambda url: print(url) 認可URLが発行されたときのコールバック。ここでは print するだけで、ブラウザを自動で開かない
01_outbound.py:17 access_token: str = "" デコレータがトークン取得完了後にこの引数へ実際の値を注入する

02_callback_server.py

client = IdentityClient(region="us-east-1")
config = json.load(open(".agentcore.json"))

@app.get("/oauth2/callback")
async def handle_callback(session_id: str):
    client.complete_resource_token_auth(
        session_uri=session_id,
        user_identifier=UserIdIdentifier(
            user_id=config["user_id"]))
    return "認証成功!このタブを閉じてください"
やってること なぜ
02_callback_server.py:7 IdentityClient(region="us-east-1") AgentCore Identity の API を呼ぶクライアントを生成
02_callback_server.py:8 config = json.load(open(".agentcore.json")) user_id を外部ファイルから読み込む。同ディレクトリに {"user_id": "..."} の内容を持つ .agentcore.json を配置する必要がある(README)
02_callback_server.py:11-17 /oauth2/callback エンドポイント OAuth プロバイダーからのリダイレクトを session_id クエリパラメータで受け取る
02_callback_server.py:13-16 client.complete_resource_token_auth(session_uri=session_id, user_identifier=UserIdIdentifier(user_id=...)) セッションとユーザーを突き合わせ、実際の OAuth トークンを AgentCore 側に確定させる。これが完了して初めて 01_outbound.py 側の access_token に値が入る
02_callback_server.py:20 uvicorn.run(app, host="127.0.0.1", port=9090) callback_url と一致するポート(9090)で待ち受ける

学んだこと(要点)

  • 3LO(three-legged OAuth)の面倒な部分(認可URL生成・コールバック受信・トークン交換)が requires_access_token 1個にラップされている。ツール本体は access_token を受け取って使うだけでよい
  • 動かすには2プロセット必要(01_outbound.py02_callback_server.py)。片方だけでは 3LO フローが完結しない
  • on_auth_url は URL を print するだけで自動オープンしない(コード上の事実)。ユーザーが手動でコピーしてブラウザを開く必要がある
  • .agentcore.jsonuser_id を外出しし、コールバックサーバーがそれを読み込む設計。ツール呼び出し元のユーザーとコールバック側の user_id をどう突き合わせているかの詳細(セッションIDとの紐付けロジック)はコードからは読み切れず、SDK 内部の挙動に依存すると推測される

落とし穴・現代版に移植するなら

  • provider_name="AtlassianProvider" は事前登録が前提。書籍本文の手順で OAuth プロバイダーを作成してからでないとコードだけでは動かない(README)
  • port 9090 が使用中だった場合は lsof -i :9090 -t | xargs kill で解放できる(README)
  • requires-python = ">=3.14"strands-agents==1.38.0bedrock-agentcore==1.6.4 で固定されている(pyproject.toml
  • on_auth_urlwebbrowser.open(url) に差し替えれば認可URLの自動オープンができそうだが、これはコードから読める事実ではなく改善案としての推測

記事参照


作成: 2026-07-17 / 最終更新: 2026-07-17