---
title: Microsoft Entra ID で WIF を使用する
url: https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure
description: Azure マネージド ID と Entra Workload Identity を Claude API とフェデレーションし、Azure ワークロードが静的な APIキーなしで Claude を呼び出せるようにします。
---

Azure ワークロードは、Microsoft Entra ID が発行した「JSON Web Token」（JSON ウェブトークン）、すなわち JWT を提示し、それを有効期間の短い Anthropic アクセストークンと交換することで Claude API に対して認証します。セットアップはどの Azure プラットフォームでも同じ形をとります。

1. **トークンのオーディエンスを登録する:** Microsoft Entra テナントに、Claude API のオーディエンスを表すアプリ登録を 1 つ作成します。テナント内のすべてのワークロードは、このオーディエンス向けの Entra トークンを要求します。
2. **プラットフォームに応じた ID をセットアップする:** VM、VM Scale Sets、App Service、Functions、Container Apps ではマネージド ID、AKS では Entra Workload Identity を使用します。
3. **Anthropic を構成する:** テナントの Entra 発行者（issuer）を登録し、サービスアカウントを作成し、トークンのクレームに一致するフェデレーションルールを記述します。
4. **実行時に交換する:** ワークロードは Entra が発行したトークンを `POST /v1/oauth/token` で `sk-ant-oat01-...` 形式の Anthropic アクセストークンと交換し、それを使って Claude を呼び出します。

どちらの経路でも、Anthropic に提示するトークンには、テナント固有の Entra 発行者と、`sub` および `oid` クレームに格納されたマネージド ID のオブジェクト ID が含まれます。異なるのは、ワークロードがそのトークンを取得する方法だけです。ワークロードの実行場所に応じたセクションを選んでください。VM、VM Scale Sets、App Service、Functions、Container Apps の場合は[マネージド ID を使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#use-a-managed-identity)、AKS の場合は [AKS で Entra Workload Identity を使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#use-entra-workload-identity-on-aks)を参照してください。

## 前提条件

* [WIF の概念](https://platform.claude.com/docs/ja/manage-claude/workload-identity-federation#concepts)（サービスアカウント、フェデレーション発行者、フェデレーションルール）を理解していること。
* マネージド ID を割り当てる権限（または AKS で Entra Workload Identity を構成する権限）を持つ Azure サブスクリプション。
* Microsoft Entra テナントにアプリ登録とサービスプリンシパルを 1 つ作成する権限（共有の Claude API オーディエンス）。Entra はテナント内に存在するオーディエンスに対してのみトークンを発行するため、トークン要求が成功するには、事前に[トークンのオーディエンスを登録する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#register-the-token-audience)手順が必要です。
* Microsoft Entra のテナント ID。Azure ポータルの **Microsoft Entra ID → Overview → Tenant ID** で確認できます。
* Anthropic 組織の Claude Console でサービスアカウント、フェデレーション発行者、フェデレーションルールを作成する権限。

## トークンのオーディエンスを登録する

Microsoft Entra ID は、要求されたオーディエンスがサービスプリンシパルを持つアプリ登録としてテナント内に存在する場合にのみトークンを発行します。Claude API のオーディエンスを表すアプリ登録を 1 つ作成してください。テナント内のすべてのワークロードがこのオーディエンス向けのトークンを要求できます。この登録がない場合、トークン要求は「resource not found in tenant」エラー（マネージド ID エンドポイントからは `AADSTS50001`、Entra トークンエンドポイントからは `AADSTS500011`）で失敗します。

```bash
# Claude APIのオーディエンスを表すアプリ登録を作成します。
APP_ID=$(az ad app create --display-name claude-api-federation --query appId -o tsv)

# v2.0アクセストークンを要求し、api://<APP_ID>の識別子URIを設定します。
az ad app update --id "$APP_ID" \
  --identifier-uris "api://$APP_ID" \
  --set api.requestedAccessTokenVersion=2

# テナント内でオーディエンスが解決されるようにサービスプリンシパルを作成します。
az ad sp create --id "$APP_ID"
```

<Note>
  `api://<APP_ID>` 形式の識別子 URI を使用してください。Entra は `https://` 形式の識別子 URI を自テナントの検証済みドメインに制限しているため、`https://api.anthropic.com` のような URI はほとんどのテナントで登録できません。`api://<APP_ID>` はどこでも受け入れられます。`requestedAccessTokenVersion: 2` を指定すると、このオーディエンス向けのトークンは v2.0 になり、本ガイドはこれを前提としています。v1.0 トークンを発行する既存の登録を再利用する場合は、[トークンが v1.0 の場合](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0)を参照してください。
</Note>

## マネージド ID を使用する

ワークロードが VM、VM Scale Set、App Service、Functions、または Container Apps で実行される場合は、この経路を使用します。ワークロードは、割り当てられたマネージド ID 用の Entra 発行 JWT をプラットフォームのローカルトークンエンドポイントから要求し、その JWT を Anthropic と交換します。

### マネージド ID を構成する

<Steps>
  <Step title="マネージド ID をアタッチする">
    Azure リソースでシステム割り当てまたはユーザー割り当てのマネージド ID を有効にします。Azure ポータルでリソースを開き、**Identity** に移動して **System assigned** をオンにします（またはユーザー割り当て ID をアタッチします）。

    ID が作成されたら、その **Object (principal) ID** を控えておきます。この GUID は発行されるトークンの `sub` クレームと `oid` クレームの両方に現れ、Anthropic のフェデレーションルールはこれに対して照合を行います。リソースの **Identity** ページで確認できます。ユーザー割り当て ID の場合は、マネージド ID リソースの **Overview** ページにある **Object (principal) ID** です。（マネージド ID は Microsoft Entra ID 内にサービスプリンシパルのみを持ち、アプリ登録は持ちません。）
  </Step>

  <Step title="プラットフォームのトークンエンドポイントを確認する">
    ID がアタッチされると、プラットフォームはローカルトークンエンドポイントを公開します。

    * **VM および VM Scale Sets:** IMDS の `http://169.254.169.254/metadata/identity/oauth2/token`。ヘッダー `Metadata: true` と `api-version=2018-02-01` を指定します。
    * **App Service、Functions、Container Apps:** 環境変数 `IDENTITY_ENDPOINT` の URL。ヘッダー `X-IDENTITY-HEADER` に `IDENTITY_HEADER` の値を設定し、`api-version=2019-08-01` を指定します。これらのプラットフォームでは IMDS には到達できません。

    リソースに複数のユーザー割り当てマネージド ID がある場合は、トークン要求に `client_id=<IDENTITY_CLIENT_ID>` を追加して 1 つを選択します。Azure は常にこれを指定することを推奨しています。指定しない場合、結果はリソースでシステム割り当て ID も有効になっているかどうかに依存します。有効になっている場合、要求は暗黙的にその ID にフォールバックし、その後フェデレーションルールの `oid` 照合に失敗します。有効になっていない場合、2 つ目のユーザー割り当て ID がアタッチされた時点で要求は即座に失敗します。
  </Step>

  <Step title="サンプルトークンをデコードする">
    エンドポイントからトークンを要求し、そのペイロードをデコードして、フェデレーションルールが照合する必要のあるクレームを確認します。（デコードコマンドについては、[失敗した交換のトラブルシューティング](https://platform.claude.com/docs/ja/manage-claude/wif-reference#troubleshoot-a-failed-exchange)を参照してください。）マネージド ID 用の v2.0 トークンには次のクレームが含まれます。

    ```json
    {
      "iss": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
      "sub": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "aud": "<APP_ID>",
      "oid": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "tid": "<TENANT_ID>",
      "azp": "<IDENTITY_CLIENT_ID>",
      "ver": "2.0",
      "exp": 1775527120
    }
    ```

    | クレーム  | 値                                                                                                                                                               | 照合するケース                                                                                                                                                          |
    | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `oid` | マネージド ID のオブジェクト ID。`sub` と同一                                                                                                                                   | 特定の 1 つのマネージド ID を認可したい場合。これがデフォルトであり、[Anthropic を構成する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#configure-anthropic)のルールはこれに照合します。 |
    | `azp` | 呼び出し元 ID のクライアント ID                                                                                                                                             | 1 つのアプリ登録を共有するすべてのワークロードを認可したい場合。マネージド ID の場合、`azp` はその ID に固有であるため、`oid` と同等です。                                                                                 |
    | `aud` | オーディエンスアプリ登録のクライアント ID（[トークンのオーディエンスを登録する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#register-the-token-audience)の `<APP_ID>` GUID） | 常に。ルールの `audience` フィールドはトークンの `aud` 値と完全に一致する必要があります。                                                                                                           |
    | `tid` | テナント ID                                                                                                                                                         | 多層防御を行いたい場合。発行者 URL がすでにテナントを固定しています。                                                                                                                            |

    デコードしたトークンの `ver` クレームが `1.0` の場合、クレーム名と値が異なります。続行する前に[トークンが v1.0 の場合](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0)を参照してください。
  </Step>
</Steps>

### Anthropic を構成する

Claude Consoleで[Workload identity](https://platform.claude.com/settings/workload-identity-federation)ページ（`platform.claude.com/settings/workload-identity-federation`）に移動し、**Connect workload** をクリックして、**Microsoft Entra** タイルを選択します。ウィザードに従って、発行者の登録、サービスアカウントの作成、フェデレーションルールの作成を行います。

ウィザードがこれらのリソースを作成します。ウィザードに入力する場合でも、[Admin API](https://platform.claude.com/docs/ja/manage-claude/wif-admin-api)に送信する場合でも、以下の値を使用してください。

**フェデレーション発行者:** ウィザードの **Token issuer** セレクターで **v2.0 (login.microsoftonline.com)** を選択します。（セレクターのデフォルトは v1 です。このデフォルトは、v1.0 トークンを発行し続ける古い登録を再利用するテナントのために存在します。）Entra はテナントごとの発行者 URL で OIDC ディスカバリードキュメントを公開しているため、ディスカバリーモードを使用してください。フェデレーションする Microsoft Entra テナントごとに、個別の発行者レコードが必要です。

```json
{
  "name": "azure-prod-tenant",
  "issuer_url": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
  "jwks": { "type": "discovery" },
  "max_jwt_lifetime_seconds": 86400
}
```

<Warning>
  マネージド ID ワークロードには `max_jwt_lifetime_seconds: 86400` が必要です。Azure は各リソースのトークンを最大 24 時間キャッシュし、早期更新を強制する手段を提供しないため、マネージド ID トークンは `iat` と `exp` の間が最大 24 時間で発行されます。発行者のデフォルトである 1 時間ではこれらのトークンが拒否されるため、交換は不透明な `401` `authentication_error` レスポンス（メッセージ `Authentication failed`）で失敗します。Connect workload ウィザードの Microsoft Entra タイルは `max_jwt_lifetime_seconds` を `7500` に設定して発行者を作成し、作成時にこれを変更するフィールドを提供しません。そのため、ウィザードを完了した後、Claude Console の [Workload identity](https://platform.claude.com/settings/workload-identity-federation) ページで **Issuers** タブを開いて発行者を編集し、値を `86400` に引き上げてください。Admin API を通じて発行者を更新することもできます。
</Warning>

受け入れる有効期間が長いほど、漏洩した Entra トークンが交換可能な状態で残る時間も長くなります。トークンが漏洩した場合の対処手段はフェデレーションルールの無効化です。[ルールのスコープを絞る](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#scope-your-rule)で説明するように、厳密な `oid` 照合によって、そもそもトークンを交換できる ID を制限できます。

**フェデレーションルール:** マネージド ID のオブジェクト ID とテナント ID に照合します。本ガイドで構成する v2.0 トークンの場合、`audience` の値はオーディエンスアプリ登録のクライアント ID（[トークンのオーディエンスを登録する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#register-the-token-audience)の `<APP_ID>` GUID）です。デコードしたトークンの `aud` 値をそのまま使用してください。

```json
{
  "name": "azure-inference-worker",
  "issuer_id": "fdis_...",
  "match": {
    "audience": "<APP_ID>",
    "claims": {
      "oid": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "tid": "<TENANT_ID>"
    }
  },
  "target": {
    "type": "service_account",
    "service_account_id": "svac_..."
  },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}
```

`token_lifetime_seconds` は、交換によって返される Anthropic アクセストークンの有効期間であり、Entra トークンの有効期間ではありません。SDK が自動的に更新します。

### トークンを取得して使用する

実行時に、ワークロードは Entra トークンを取得し、`POST /v1/oauth/token` で交換し、返されたベアラートークンを使用して Claude を呼び出します。次の例に示すように、`identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) を指定すると、Claude SDK が交換と更新のループを処理します。Java（その例のコメントを参照）を除き、このオプションはトークンプロバイダーを受け取り、SDK は更新のたびにそれを再度呼び出します。cURL タブは生のフローを示しています。

サンプルは、プラットフォームのトークンエンドポイント（VM および VM Scale Sets では IMDS、App Service、Functions、Container Apps では `IDENTITY_ENDPOINT` サービス）からマネージド ID トークンを取得します。`api://<APP_ID>` リソース値の `<APP_ID>` を、[トークンのオーディエンスを登録する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#register-the-token-audience)で取得したオーディエンスアプリ登録のクライアント ID に置き換えてください。

<Tip>
  ワークロードがすでに Azure Identity クライアントライブラリを使用している場合は、トークンエンドポイントを直接呼び出す代わりに、そのライブラリ（スコープ `api://<APP_ID>/.default` を指定した `DefaultAzureCredential`）から Entra トークンを取得してください。例と同じ方法で、それを `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) に渡してください。このライブラリは、Entra Workload Identity を使用する AKS を含め、すべての Azure プラットフォームで正しいエンドポイントを選択します。
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Entra が発行したトークンを取得します（managed identity（マネージド ID））。
  #    VM または VM Scale Set では IMDS を使用します。ユーザー割り当て ID が複数ある場合は、
  #    &client_id=<IDENTITY_CLIENT_ID> を末尾に追加します。
  ENTRA_TOKEN=$(curl -sS -H "Metadata: true" \
    "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api://<APP_ID>" \
    | jq -r .access_token)

  #    App Service、Functions、Container Apps では、代わりにローカルのトークン
  #    サービスを使用します（これらの環境では IMDS に到達できません）：
  # ENTRA_TOKEN=$(curl -sS -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" \
  #   "$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=api://<APP_ID>" \
  #   | jq -r .access_token)

  #    Entra Workload Identity を使用する AKS の場合は、代わりに
  #    「Use Entra Workload Identity on AKS」セクションの 2 段階の交換を使用します。

  # 2. これを Anthropic のアクセストークンと交換します。
  RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    -H "content-type: application/json" \
    -d @- <<JSON
  {
    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "assertion": "$ENTRA_TOKEN",
    "federation_rule_id": "$ANTHROPIC_FEDERATION_RULE_ID",
    "organization_id": "$ANTHROPIC_ORGANIZATION_ID",
    "service_account_id": "$ANTHROPIC_SERVICE_ACCOUNT_ID",
    "workspace_id": "$ANTHROPIC_WORKSPACE_ID"
  }
  JSON
  )

  ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)

  # 3. ベアラートークンを使用して Claude API を呼び出します。
  curl https://api.anthropic.com/v1/messages \
    -H "authorization: Bearer $ACCESS_TOKEN" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "messages": [{"role": "user", "content": "Hello from Azure"}]
    }' | jq -r '.content[] | select(.type == "text") | .text'
  ```

  ```python Python
  import os

  import anthropic
  import requests
  from anthropic import WorkloadIdentityCredentials

  # オーディエンスのアプリ登録の識別子URIです（「トークンオーディエンスを登録する」を参照）。
  AUDIENCE = "api://<APP_ID>"


  def fetch_entra_token() -> str:
      """Fetch a managed identity token from the platform's token endpoint."""
      # ユーザー割り当てマネージドIDが複数ある場合は、client_id=<IDENTITY_CLIENT_ID> を
      # リクエストパラメーターに追加して、使用するIDを1つ選択します。
      if endpoint := os.environ.get("IDENTITY_ENDPOINT"):
          # App Service、Functions、Container Apps
          response = requests.get(
              endpoint,
              headers={"X-IDENTITY-HEADER": os.environ["IDENTITY_HEADER"]},
              params={"api-version": "2019-08-01", "resource": AUDIENCE},
              timeout=5,
          )
      else:
          # VM または VM Scale Set: Azure Instance Metadata Service (IMDS)
          response = requests.get(
              "http://169.254.169.254/metadata/identity/oauth2/token",
              headers={"Metadata": "true"},
              params={"api-version": "2018-02-01", "resource": AUDIENCE},
              timeout=5,
          )
      response.raise_for_status()
      return response.json()["access_token"]


  client = anthropic.Anthropic(
      credentials=WorkloadIdentityCredentials(
          identity_token_provider=fetch_entra_token,
          federation_rule_id=os.environ["ANTHROPIC_FEDERATION_RULE_ID"],
          organization_id=os.environ["ANTHROPIC_ORGANIZATION_ID"],
          service_account_id=os.environ["ANTHROPIC_SERVICE_ACCOUNT_ID"],
          workspace_id=os.environ.get("ANTHROPIC_WORKSPACE_ID"),
      ),
  )

  message = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello from Azure"}],
  )
  print(next(block.text for block in message.content if block.type == "text"))
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import { oidcFederationProvider } from "@anthropic-ai/sdk/lib/credentials/oidc-federation";

  // オーディエンス用アプリ登録の識別子 URI です（「トークンオーディエンスを登録する」を参照）。
  const AUDIENCE = "api://<APP_ID>";

  async function fetchEntraToken(): Promise<string> {
    // App Service、Functions、Container Apps は IDENTITY_ENDPOINT を挿入します。
    // VM と VM Scale Sets は IMDS を使用します。
    // ユーザー割り当て ID が複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
    const identityEndpoint = process.env.IDENTITY_ENDPOINT;
    const url = identityEndpoint
      ? `${identityEndpoint}?api-version=2019-08-01&resource=${AUDIENCE}`
      : `http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=${AUDIENCE}`;
    const headers: Record<string, string> = identityEndpoint
      ? { "X-IDENTITY-HEADER": process.env.IDENTITY_HEADER! }
      : { Metadata: "true" };
    const response = await fetch(url, { headers });
    const body = (await response.json()) as { access_token: string };
    return body.access_token;
  }

  const client = new Anthropic({
    credentials: oidcFederationProvider({
      identityTokenProvider: fetchEntraToken,
      federationRuleId: process.env.ANTHROPIC_FEDERATION_RULE_ID!,
      organizationId: process.env.ANTHROPIC_ORGANIZATION_ID!,
      serviceAccountId: process.env.ANTHROPIC_SERVICE_ACCOUNT_ID,
      workspaceId: process.env.ANTHROPIC_WORKSPACE_ID,
      baseURL: "https://api.anthropic.com",
      fetch
    })
  });

  const message = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello from Azure" }]
  });
  for (const block of message.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  ```

  ```go Go
  package main

  import (
  	"context"
  	"encoding/json"
  	"fmt"
  	"net/http"
  	"os"

  	"github.com/anthropics/anthropic-sdk-go"
  	"github.com/anthropics/anthropic-sdk-go/option"
  )

  // オーディエンスのアプリ登録の識別子 URI です（「トークンオーディエンスを登録する」を参照）。
  const audience = "api://<APP_ID>"

  // fetchEntraToken は、プラットフォームのトークンエンドポイントからマネージド ID トークンを取得します
  // （VM および VM Scale Sets では IMDS、
  // App Service、Functions、Container Apps では IDENTITY_ENDPOINT サービス）。
  func fetchEntraToken(ctx context.Context) (string, error) {
  	// ユーザー割り当て ID が複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
  	tokenURL := "http://169.254.169.254/metadata/identity/oauth2/token" +
  		"?api-version=2018-02-01&resource=" + audience
  	header, value := "Metadata", "true"
  	if endpoint := os.Getenv("IDENTITY_ENDPOINT"); endpoint != "" {
  		tokenURL = endpoint + "?api-version=2019-08-01&resource=" + audience
  		header, value = "X-IDENTITY-HEADER", os.Getenv("IDENTITY_HEADER")
  	}
  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, tokenURL, nil)
  	if err != nil {
  		return "", err
  	}
  	req.Header.Set(header, value)
  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		return "", fmt.Errorf("call token endpoint: %w", err)
  	}
  	defer resp.Body.Close()
  	var body struct {
  		AccessToken string `json:"access_token"`
  	}
  	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
  		return "", fmt.Errorf("decode token response: %w", err)
  	}
  	return body.AccessToken, nil
  }

  func main() {
  	client := anthropic.NewClient(
  		option.WithFederationTokenProvider(fetchEntraToken, option.FederationOptions{
  			FederationRuleID: os.Getenv("ANTHROPIC_FEDERATION_RULE_ID"),
  			OrganizationID:   os.Getenv("ANTHROPIC_ORGANIZATION_ID"),
  			ServiceAccountID: os.Getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"),
  			WorkspaceID:      os.Getenv("ANTHROPIC_WORKSPACE_ID"),
  		}),
  	)

  	message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 1024,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock("Hello from Azure")),
  		},
  	})
  	if err != nil {
  		panic(err)
  	}
  	for _, block := range message.Content {
  		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  			fmt.Println(textBlock.Text)
  			break
  		}
  	}
  }
  ```

  ```java Java
  import com.anthropic.config.AuthenticationConfig;
  import com.anthropic.config.AuthenticationType;
  import com.anthropic.config.IdentityTokenConfig;
  import com.anthropic.config.InMemoryProfileConfigProvider;
  import com.anthropic.config.ProfileConfig;
  // ...
  import com.fasterxml.jackson.databind.ObjectMapper;
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  void main() throws Exception {
      HttpClient http = HttpClient.newHttpClient();
      // オーディエンス用アプリ登録の識別子 URI です（「トークンオーディエンスを登録する」を参照）。
      String audience = "api://<APP_ID>";
      // App Service、Functions、Container Apps は IDENTITY_ENDPOINT を挿入します。
      // VM と VM Scale Sets は IMDS を使用します。
      // ユーザー割り当て ID が複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
      String identityEndpoint = System.getenv("IDENTITY_ENDPOINT");
      HttpRequest tokenRequest = identityEndpoint != null
              ? HttpRequest.newBuilder(URI.create(identityEndpoint + "?api-version=2019-08-01&resource=" + audience))
                      .header("X-IDENTITY-HEADER", System.getenv("IDENTITY_HEADER"))
                      .build()
              : HttpRequest.newBuilder(URI.create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=" + audience))
                      .header("Metadata", "true")
                      .build();

      // Java SDK は関数ではなく、トークン自体またはファイルパスを受け取ります。
      // source("value") の場合、path(...) がトークンを保持します。SDK は同じトークンを
      // Anthropic アクセストークンの更新のたびに送信するため、トークンが
      // 期限切れになるか、jti クレームがある場合は使用済みになると失敗します。長時間実行される
      // プロセスでは、source("file") を渡し、各更新の前に新しいトークンを
      // ファイルに書き込んでください。
      var response = http.send(tokenRequest, HttpResponse.BodyHandlers.ofString());
      String entraToken = new ObjectMapper().readTree(response.body()).get("access_token").asText();

      AnthropicClient client = AnthropicOkHttpClient.builder()
              .configurationProvider(InMemoryProfileConfigProvider.of(ProfileConfig.builder()
                      .organizationId(System.getenv("ANTHROPIC_ORGANIZATION_ID"))
                      .workspaceId(System.getenv("ANTHROPIC_WORKSPACE_ID"))
                      .authentication(AuthenticationConfig.builder()
                              .type(AuthenticationType.OIDC_FEDERATION)
                              .federationRuleId(System.getenv("ANTHROPIC_FEDERATION_RULE_ID"))
                              .serviceAccountId(System.getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"))
                              .identityToken(IdentityTokenConfig.builder()
                                      .source("value")
                                      .path(entraToken)
                                      .build())
                              .build())
                      .build()))
              .build();

      var message = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024)
              .addUserMessage("Hello from Azure")
              .build());

      IO.println(message.content());
  }
  ```

  ```csharp C#
  using Anthropic.Credentials;
  // ...

  var credentials = new WorkloadIdentityCredentials(new WorkloadIdentityOptions
  {
      FederationRuleId = Environment.GetEnvironmentVariable("ANTHROPIC_FEDERATION_RULE_ID")!,
      OrganizationId = Environment.GetEnvironmentVariable("ANTHROPIC_ORGANIZATION_ID"),
      ServiceAccountId = Environment.GetEnvironmentVariable("ANTHROPIC_SERVICE_ACCOUNT_ID"),
      WorkspaceId = Environment.GetEnvironmentVariable("ANTHROPIC_WORKSPACE_ID"),
      IdentityTokenProvider = new EntraTokenProvider(),
  });
  using var client = new AnthropicClient(new ClientOptions { Credentials = credentials });

  var message = await client.Messages.Create(new()
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [new() { Role = Role.User, Content = "Hello from Azure" }],
  });
  foreach (var block in message.Content)
  {
      if (block.Value is TextBlock textBlock)
      {
          Console.WriteLine(textBlock.Text);
      }
  }

  class EntraTokenProvider : IIdentityTokenProvider
  {
      // オーディエンス用アプリ登録の識別子 URI です（「トークンオーディエンスを登録する」を参照）。
      private const string Audience = "api://<APP_ID>";

      private static readonly HttpClient httpClient = new();

      public async Task<string> GetIdentityTokenAsync(CancellationToken ct = default)
      {
          // App Service、Functions、Container Apps は IDENTITY_ENDPOINT を挿入します。
          // VM と VM Scale Sets は IMDS を使用します。
          // ユーザー割り当てマネージド ID が複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
          var identityEndpoint = Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT");
          using var request = identityEndpoint is not null
              ? new HttpRequestMessage(HttpMethod.Get,
                  $"{identityEndpoint}?api-version=2019-08-01&resource={Audience}")
              {
                  Headers = { { "X-IDENTITY-HEADER", Environment.GetEnvironmentVariable("IDENTITY_HEADER") } },
              }
              : new HttpRequestMessage(HttpMethod.Get,
                  $"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource={Audience}")
              {
                  Headers = { { "Metadata", "true" } },
              };
          using var response = await httpClient.SendAsync(request, ct);
          response.EnsureSuccessStatusCode();
          using var json = await JsonDocument.ParseAsync(
              await response.Content.ReadAsStreamAsync(ct), default, ct);
          return json.RootElement.GetProperty("access_token").GetString()!;
      }
  }
  ```

  ```php PHP
  use Anthropic\Client;
  use Anthropic\Lib\Credentials\CredentialResult;
  use Anthropic\Lib\Credentials\IdentityTokenProvider;
  use Anthropic\Lib\Credentials\TokenCache;
  use Anthropic\Lib\Credentials\WorkloadIdentityCredentials;

  // オーディエンス用アプリ登録の識別子 URI です（「トークンオーディエンスを登録する」を参照）。
  const AUDIENCE = 'api://<APP_ID>';

  class EntraIdentityToken implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          // App Service、Functions、Container Apps は IDENTITY_ENDPOINT を挿入します。
          // VM と VM Scale Sets は IMDS を使用します。
          // ユーザー割り当て ID が複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
          $identityEndpoint = getenv('IDENTITY_ENDPOINT');
          if ($identityEndpoint !== false) {
              $url = $identityEndpoint . '?api-version=2019-08-01&resource=' . AUDIENCE;
              $header = 'X-IDENTITY-HEADER: ' . getenv('IDENTITY_HEADER');
          } else {
              $url = 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=' . AUDIENCE;
              $header = 'Metadata: true';
          }
          $context = stream_context_create([
              'http' => ['header' => $header . "\r\n"],
          ]);
          $body = json_decode(file_get_contents($url, false, $context), true);
          return $body['access_token'];
      }
  }

  $credentials = new CredentialResult(
      provider: new TokenCache(new WorkloadIdentityCredentials(
          identityProvider: new EntraIdentityToken(),
          federationRuleId: getenv('ANTHROPIC_FEDERATION_RULE_ID'),
          organizationId: getenv('ANTHROPIC_ORGANIZATION_ID'),
          serviceAccountId: getenv('ANTHROPIC_SERVICE_ACCOUNT_ID'),
          workspaceId: getenv('ANTHROPIC_WORKSPACE_ID') ?: null,
      )),
  );
  $client = new Client(credentials: $credentials);

  $message = $client->messages->create(
      model: 'claude-opus-5-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello from Azure']],
  );
  $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
  echo $textBlock->text, PHP_EOL;
  ```

  ```ruby Ruby
  require "anthropic"
  require "json"
  require "net/http"

  # オーディエンスのアプリ登録の識別子URIです（「トークンオーディエンスを登録する」を参照）。
  AUDIENCE = "api://<APP_ID>"

  def fetch_entra_token
    # App Service、Functions、Container Apps は IDENTITY_ENDPOINT を挿入します。
    # VM と VM Scale Sets は IMDS を使用します。
    # ユーザー割り当てIDが複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
    if (endpoint = ENV["IDENTITY_ENDPOINT"])
      url = "#{endpoint}?api-version=2019-08-01&resource=#{AUDIENCE}"
      headers = {"X-IDENTITY-HEADER" => ENV.fetch("IDENTITY_HEADER")}
    else
      url = "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=#{AUDIENCE}"
      headers = {"Metadata" => "true"}
    end
    response = Net::HTTP.get(URI(url), headers)
    JSON.parse(response).fetch("access_token")
  end

  credentials = Anthropic::WorkloadIdentityCredentials.new(
    identity_token_provider: -> { fetch_entra_token },
    federation_rule_id: ENV.fetch("ANTHROPIC_FEDERATION_RULE_ID"),
    organization_id: ENV.fetch("ANTHROPIC_ORGANIZATION_ID"),
    service_account_id: ENV.fetch("ANTHROPIC_SERVICE_ACCOUNT_ID"),
    workspace_id: ENV["ANTHROPIC_WORKSPACE_ID"]
  )
  client = Anthropic::Client.new(credentials: credentials)

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello from Azure"}]
  )
  puts message.content.find { it.type == :text }.text
  ```

  ```bash CLI
  # Entraが発行したアクセストークンを、CLIが読み取れるファイルに書き込みます。
  # VMまたはVM Scale Set（IMDS）の場合の例です。App Service、Functions、または
  # Container Appsでは、代わりに "$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=api://<APP_ID>" から
  # -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" を付けて取得します。
  # ユーザー割り当てIDが複数ある場合は、&client_id=<IDENTITY_CLIENT_ID> を追加します。
  ANTHROPIC_IDENTITY_TOKEN_FILE=$(mktemp)
  trap 'rm -f "$ANTHROPIC_IDENTITY_TOKEN_FILE"' EXIT
  curl -sS -H "Metadata: true" \
    "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=api://<APP_ID>" \
    | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
  export ANTHROPIC_IDENTITY_TOKEN_FILE

  # ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  # ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID は環境変数から読み取られます。
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### セットアップを検証する

Azure リソースから、[トークンを取得して使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#acquire-and-use-the-token)に示した cURL による交換を実行し、`POST /v1/oauth/token` が `200` を返し、`sk-ant-oat01-` で始まる `access_token` と秒単位の `expires_in` 値が含まれていることを確認します。交換が不透明な `401` `authentication_error` レスポンス（メッセージ `Authentication failed`）で失敗した場合は、Claude Console の[認証履歴ページ](https://platform.claude.com/settings/workload-identity-federation?tab=history)で拒否理由を確認し、Entra トークンをデコードして（コマンドは[失敗した交換のトラブルシューティング](https://platform.claude.com/docs/ja/manage-claude/wif-reference#troubleshoot-a-failed-exchange)を参照）、Azure 側で最も一般的な原因を確認してください。

* **発行者の不一致:** 登録した `issuer_url` はトークンの `iss` クレームと完全に一致する必要があります。v2.0 トークンには `https://login.microsoftonline.com/<TENANT_ID>/v2.0` が含まれます。デコードした `ver` クレームが `1.0` の場合は、[トークンが v1.0 の場合](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0)を参照してください。
* **トークンの有効期間:** マネージド ID トークンは `iat` と `exp` の間が最大 24 時間です。発行者がウィザードの `7500`（または 1 時間のデフォルト）のままの場合は、[Anthropic を構成する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#configure-anthropic)で説明したように `max_jwt_lifetime_seconds` を `86400` に引き上げてください。
* **オーディエンスの不一致:** ルールの `audience` はトークンの `aud` と完全に一致する必要があります。本ガイドで構成する v2.0 トークンの場合は、オーディエンスアプリ登録のクライアント ID です。
* **クレーム名の不一致:** トークンに含まれないクレームに照合するルールは決して通過しません。v1.0 トークンはクライアント ID を `azp` ではなく `appid` に格納します。[トークンが v1.0 の場合](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0)を参照してください。

## AKS で Entra Workload Identity を使用する

ワークロードが AKS ポッドで実行される場合は、この経路を使用します。Entra Workload Identity は Kubernetes サービスアカウントをユーザー割り当てマネージド ID とフェデレーションします。Kubernetes は、サービスアカウントトークン（AKS クラスターの OIDC 発行者によって署名されたもの）を `AZURE_FEDERATED_TOKEN_FILE` のパスでポッドに投影します。この投影されたトークンは Entra が発行したトークンではないため、本ページで説明する Entra 経由の経路にとどまるには、ワークロードは 2 ホップの交換を行います。まず投影されたトークンを `https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token`（フェデレーション `client_credentials` グラント）で Entra 発行のアクセストークンに引き換え、次にその Entra トークンを ID トークンとして Anthropic SDK に渡します。

<Tip>
  AKS ポッドは、代わりに Entra の交換をスキップして、Kubernetes が投影したサービスアカウントトークンを Anthropic に直接提示することもできます。その経路では、Entra テナントの代わりに AKS クラスターの OIDC 発行者を Anthropic に登録します。そのフローについては [Kubernetes で WIF を使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/kubernetes)を参照してください。
</Tip>

### Entra Workload Identity を構成する

<Steps>
  <Step title="クラスターで OIDC 発行者とワークロード ID を有効にする">
    ワークロード ID を有効にすると、`azure-workload-identity` ミューテーティング Webhook が自動的にインストールされます。手動でデプロイするのは AKS 以外のクラスターの場合のみです。後の手順で作成するフェデレーション資格情報のために、クラスターの OIDC 発行者 URL を取得しておきます。

    ```bash
    az aks update \
      --resource-group <RESOURCE_GROUP> \
      --name <CLUSTER_NAME> \
      --enable-oidc-issuer \
      --enable-workload-identity

    AKS_OIDC_ISSUER=$(az aks show \
      --resource-group <RESOURCE_GROUP> \
      --name <CLUSTER_NAME> \
      --query oidcIssuerProfile.issuerUrl -o tsv)
    ```
  </Step>

  <Step title="ユーザー割り当てマネージド ID を作成する">
    ID から 2 つの値を取得します。**Client ID** はサービスアカウントのアノテーションに設定し（ポッドには `AZURE_CLIENT_ID` として注入されます）、**Object (principal) ID** は Anthropic のフェデレーションルールが照合する `oid` クレームとして現れます。

    ```bash
    az identity create \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --location <LOCATION>

    # サービスアカウントのアノテーションに設定します。Pod には AZURE_CLIENT_ID として注入されます。
    IDENTITY_CLIENT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query clientId -o tsv)

    # フェデレーションルールが照合する oid クレームとして表示されます。
    IDENTITY_OBJECT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query principalId -o tsv)
    ```
  </Step>

  <Step title="アノテーション付きの Kubernetes サービスアカウントを作成する">
    `azure-workload-identity` Webhook は `azure.workload.identity/client-id` アノテーションを読み取って `AZURE_CLIENT_ID` をポッドに注入します。[トークンを取得して使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#acquire-and-use-the-token-2)のサンプルはこれを環境から読み取ります。

    ```yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: claude-inference
      namespace: inference
      annotations:
        azure.workload.identity/client-id: <IDENTITY_CLIENT_ID>
    ```
  </Step>

  <Step title="マネージド ID にフェデレーション資格情報を作成する">
    フェデレーション資格情報は、その特定のサービスアカウントについてクラスターの OIDC 発行者を信頼します。`--audience api://AzureADTokenExchange` の値は、受信する Kubernetes サービスアカウントトークンに対する Entra の固定オーディエンスであり、先に登録した Claude API のオーディエンスとは無関係です。

    ```bash
    az identity federated-credential create \
      --resource-group <RESOURCE_GROUP> \
      --identity-name claude-inference-identity \
      --name claude-inference-aks \
      --issuer "$AKS_OIDC_ISSUER" \
      --subject system:serviceaccount:inference:claude-inference \
      --audience api://AzureADTokenExchange
    ```
  </Step>

  <Step title="ポッドにラベルを付け、サービスアカウントを設定する">
    ポッドには `azure.workload.identity/use: "true"` ラベルが必要で、アノテーション付きのサービスアカウントとして実行する必要があります。すると Webhook が `AZURE_FEDERATED_TOKEN_FILE`、`AZURE_CLIENT_ID`、`AZURE_TENANT_ID` をポッドに注入します。`AZURE_FEDERATED_TOKEN_FILE` のファイルには、AKS クラスターの OIDC 発行者によって署名された、Kubernetes が投影したサービスアカウントトークンが含まれます。

    ```yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: inference-worker
      namespace: inference
      labels:
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: claude-inference
      containers:
        - name: app
          image: your-registry/inference-worker:latest
    ```
  </Step>

  <Step title="サンプルトークンをデコードする">
    Anthropic のフェデレーションルールが参照するトークンは投影されたファイルではなく、`client_credentials` 交換によって返される Entra 発行のトークンです。ラベル付きポッドの内部から、[トークンを取得して使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#acquire-and-use-the-token-2)の cURL サンプルのステップ 1 を実行し、結果をデコードします。マネージド ID 経路と同じクレーム構造を持ちます。

    ```json
    {
      "iss": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
      "sub": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "aud": "<APP_ID>",
      "oid": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "tid": "<TENANT_ID>",
      "azp": "<IDENTITY_CLIENT_ID>",
      "ver": "2.0",
      "exp": 1775527120
    }
    ```

    `sub` と `oid` はマネージド ID のオブジェクト ID、`aud` はオーディエンスアプリ登録のクライアント ID、`azp` はマネージド ID のクライアント ID（`AZURE_CLIENT_ID` の値）です。有効期間はマネージド ID 経路と異なります。`client_credentials` トークンは、`iat` と `exp` の間がデフォルトで 24 時間ではなく、60 〜 90 分のランダムな期間になります。
  </Step>
</Steps>

### Anthropic を構成する

Claude Consoleで[Workload identity](https://platform.claude.com/settings/workload-identity-federation)ページ（`platform.claude.com/settings/workload-identity-federation`）に移動し、**Connect workload** をクリックして、**Microsoft Entra** タイルを選択します。ウィザードに従って、発行者の登録、サービスアカウントの作成、フェデレーションルールの作成を行います。

ウィザードがこれらのリソースを作成します。ウィザードに入力する場合でも、[Admin API](https://platform.claude.com/docs/ja/manage-claude/wif-admin-api)に送信する場合でも、以下の値を使用してください。

**フェデレーション発行者:** ウィザードの **Token issuer** セレクターで **v2.0 (login.microsoftonline.com)** を選択します。（セレクターのデフォルトは v1 です。このデフォルトは、v1.0 トークンを発行し続ける古い登録を再利用するテナントのために存在します。）Entra はテナントごとの発行者 URL で OIDC ディスカバリードキュメントを公開しているため、ディスカバリーモードを使用してください。フェデレーションする Microsoft Entra テナントごとに、個別の発行者レコードが必要です。

```json
{
  "name": "azure-prod-tenant",
  "issuer_url": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
  "jwks": { "type": "discovery" },
  "max_jwt_lifetime_seconds": 7500
}
```

<Warning>
  Connect workload ウィザードの Microsoft Entra タイルは、`max_jwt_lifetime_seconds` を `7500`（2 時間強）に設定して発行者を作成します。これは `client_credentials` トークンのデフォルトの有効期間である 60 〜 90 分をカバーします。テナントのトークン有効期間ポリシーや「Continuous Access Evaluation」（継続的アクセス評価）、すなわち CAE によって、この有効期間が延長される場合があります。デコードしたトークンの `exp` から `iat` を引いた値が 7500 秒を超える場合は、Claude Console の [Workload identity](https://platform.claude.com/settings/workload-identity-federation) ページの **Issuers** タブで発行者を編集し、それに合わせて `max_jwt_lifetime_seconds` を引き上げてください。そうしないと、交換は不透明な `401` `authentication_error` レスポンス（メッセージ `Authentication failed`）で失敗します。テナントで[マネージド ID を使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#use-a-managed-identity)のマネージド ID ワークロードも実行している場合は、両方の経路をカバーするそのセクションの `86400` の値を使用してください。
</Warning>

受け入れる有効期間が長いほど、漏洩した Entra トークンが交換可能な状態で残る時間も長くなります。トークンが漏洩した場合の対処手段はフェデレーションルールの無効化です。[ルールのスコープを絞る](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#scope-your-rule)で説明するように、厳密な `oid` 照合によって、そもそもトークンを交換できる ID を制限できます。

**フェデレーションルール:** マネージド ID のオブジェクト ID とテナント ID に照合します。本ガイドで構成する v2.0 トークンの場合、`audience` の値はオーディエンスアプリ登録のクライアント ID（[トークンのオーディエンスを登録する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#register-the-token-audience)の `<APP_ID>` GUID）です。デコードしたトークンの `aud` 値をそのまま使用してください。

```json
{
  "name": "azure-inference-worker",
  "issuer_id": "fdis_...",
  "match": {
    "audience": "<APP_ID>",
    "claims": {
      "oid": "9f8e7d6c-1a2b-3c4d-5e6f-...",
      "tid": "<TENANT_ID>"
    }
  },
  "target": {
    "type": "service_account",
    "service_account_id": "svac_..."
  },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}
```

`token_lifetime_seconds` は、交換によって返される Anthropic アクセストークンの有効期間であり、Entra トークンの有効期間ではありません。SDK が自動的に更新します。

### トークンを取得して使用する

実行時に、ポッドは 2 段階の交換を行います。Kubernetes が投影したトークン（`AZURE_FEDERATED_TOKEN_FILE` のファイル）をフェデレーション `client_credentials` アサーションとして Entra のトークンエンドポイントに送信し、得られた Entra アクセストークンを `POST /v1/oauth/token` で交換します。次の例に示すように、`identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) を指定すると、Claude SDK が 2 回目の交換と更新のループを処理します。Java（その例のコメントを参照）を除き、このオプションは Entra からの取得処理をトークンプロバイダーとして受け取り、SDK は更新のたびにそれを再度呼び出します。cURL タブは生のフローを示しています。

サンプルには 2 つの異なるクライアント ID が登場します。`<APP_ID>` は[トークンのオーディエンスを登録する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#register-the-token-audience)で取得したオーディエンスアプリ登録のクライアント ID であり、スコープ `api://<APP_ID>/.default` はそのオーディエンス宛てのトークンを Entra に要求します。`$AZURE_CLIENT_ID` は Webhook によって注入されるマネージド ID のクライアント ID であり、呼び出し元を識別します。両者を取り違えないでください。

<Tip>
  ワークロードがすでに Azure Identity クライアントライブラリを使用している場合は、2 段階の交換を自分で行う代わりに、そのライブラリ（スコープ `api://<APP_ID>/.default` を指定した `DefaultAzureCredential`）から Entra トークンを取得してください。例と同じ方法で、それを `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) に渡してください。このライブラリは同じ `AZURE_FEDERATED_TOKEN_FILE`、`AZURE_CLIENT_ID`、`AZURE_TENANT_ID` 環境変数を読み取り、Entra の交換を処理します。
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Kubernetes が投影したトークン（$AZURE_FEDERATED_TOKEN_FILE にあります）を
  #    Entra が発行した JWT と交換します。
  ENTRA_JWT=$(curl -sS "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \
    -d grant_type=client_credentials \
    -d "client_id=$AZURE_CLIENT_ID" \
    --data-urlencode "scope=api://<APP_ID>/.default" \
    -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
    --data-urlencode "client_assertion@$AZURE_FEDERATED_TOKEN_FILE" \
    | jq -r .access_token)

  # 2. Entra の JWT を Anthropic のアクセストークンと交換します。
  ACCESS_TOKEN=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    -H "content-type: application/json" \
    -d @- <<JSON | jq -r .access_token
  {
    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "assertion": "$ENTRA_JWT",
    "federation_rule_id": "$ANTHROPIC_FEDERATION_RULE_ID",
    "organization_id": "$ANTHROPIC_ORGANIZATION_ID",
    "service_account_id": "$ANTHROPIC_SERVICE_ACCOUNT_ID",
    "workspace_id": "$ANTHROPIC_WORKSPACE_ID"
  }
  JSON
  )

  # 3. Claude API を呼び出します。
  curl -sS https://api.anthropic.com/v1/messages \
    -H "authorization: Bearer $ACCESS_TOKEN" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "messages": [{"role": "user", "content": "Hello from Azure"}]
    }' | jq -r '.content[] | select(.type == "text") | .text'
  ```

  ```python Python
  import os
  from pathlib import Path

  import anthropic
  import requests
  from anthropic import WorkloadIdentityCredentials


  def fetch_entra_token_via_federation() -> str:
      federated_token = Path(os.environ["AZURE_FEDERATED_TOKEN_FILE"]).read_text()
      response = requests.post(
          f"https://login.microsoftonline.com/{os.environ['AZURE_TENANT_ID']}/oauth2/v2.0/token",
          data={
              "client_id": os.environ["AZURE_CLIENT_ID"],
              "grant_type": "client_credentials",
              "scope": "api://<APP_ID>/.default",
              "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
              "client_assertion": federated_token,
          },
          timeout=5,
      )
      response.raise_for_status()
      return response.json()["access_token"]


  client = anthropic.Anthropic(
      credentials=WorkloadIdentityCredentials(
          identity_token_provider=fetch_entra_token_via_federation,
          federation_rule_id=os.environ["ANTHROPIC_FEDERATION_RULE_ID"],
          organization_id=os.environ["ANTHROPIC_ORGANIZATION_ID"],
          service_account_id=os.environ["ANTHROPIC_SERVICE_ACCOUNT_ID"],
          workspace_id=os.environ.get("ANTHROPIC_WORKSPACE_ID"),
      ),
  )

  message = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[{"role": "user", "content": "Hello from Azure"}],
  )
  print(next(block.text for block in message.content if block.type == "text"))
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import { oidcFederationProvider } from "@anthropic-ai/sdk/lib/credentials/oidc-federation";
  import { readFile } from "node:fs/promises";

  async function fetchEntraTokenViaFederation(): Promise<string> {
    const federatedToken = await readFile(process.env.AZURE_FEDERATED_TOKEN_FILE!, "utf8");
    const response = await fetch(
      `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}/oauth2/v2.0/token`,
      {
        method: "POST",
        headers: { "content-type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams({
          client_id: process.env.AZURE_CLIENT_ID!,
          grant_type: "client_credentials",
          scope: "api://<APP_ID>/.default",
          client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
          client_assertion: federatedToken
        })
      }
    );
    const body = (await response.json()) as { access_token: string };
    return body.access_token;
  }

  const client = new Anthropic({
    credentials: oidcFederationProvider({
      identityTokenProvider: fetchEntraTokenViaFederation,
      federationRuleId: process.env.ANTHROPIC_FEDERATION_RULE_ID!,
      organizationId: process.env.ANTHROPIC_ORGANIZATION_ID!,
      serviceAccountId: process.env.ANTHROPIC_SERVICE_ACCOUNT_ID,
      workspaceId: process.env.ANTHROPIC_WORKSPACE_ID,
      baseURL: "https://api.anthropic.com",
      fetch
    })
  });

  const message = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Hello from Azure" }]
  });
  for (const block of message.content) {
    if (block.type === "text") {
      console.log(block.text);
    }
  }
  ```

  ```go Go
  package main

  import (
  	"context"
  	"encoding/json"
  	"fmt"
  	"net/http"
  	"net/url"
  	"os"
  	"strings"

  	"github.com/anthropics/anthropic-sdk-go"
  	"github.com/anthropics/anthropic-sdk-go/option"
  )

  func fetchEntraTokenViaFederation(ctx context.Context) (string, error) {
  	federatedToken, err := os.ReadFile(os.Getenv("AZURE_FEDERATED_TOKEN_FILE"))
  	if err != nil {
  		return "", err
  	}
  	form := url.Values{
  		"client_id":             {os.Getenv("AZURE_CLIENT_ID")},
  		"grant_type":            {"client_credentials"},
  		"scope":                 {"api://<APP_ID>/.default"},
  		"client_assertion_type": {"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
  		"client_assertion":      {strings.TrimSpace(string(federatedToken))},
  	}
  	tokenURL := "https://login.microsoftonline.com/" + os.Getenv("AZURE_TENANT_ID") + "/oauth2/v2.0/token"
  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, tokenURL, strings.NewReader(form.Encode()))
  	if err != nil {
  		return "", err
  	}
  	req.Header.Set("content-type", "application/x-www-form-urlencoded")
  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		return "", err
  	}
  	defer resp.Body.Close()
  	var body struct {
  		AccessToken string `json:"access_token"`
  	}
  	if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
  		return "", err
  	}
  	return body.AccessToken, nil
  }

  func main() {
  	client := anthropic.NewClient(
  		option.WithFederationTokenProvider(option.IdentityTokenFunc(fetchEntraTokenViaFederation), option.FederationOptions{
  			FederationRuleID: os.Getenv("ANTHROPIC_FEDERATION_RULE_ID"),
  			OrganizationID:   os.Getenv("ANTHROPIC_ORGANIZATION_ID"),
  			ServiceAccountID: os.Getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"),
  			WorkspaceID:      os.Getenv("ANTHROPIC_WORKSPACE_ID"),
  		}),
  	)
  	message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 1024,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock("Hello from Azure")),
  		},
  	})
  	if err != nil {
  		panic(err)
  	}
  	for _, block := range message.Content {
  		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  			fmt.Println(textBlock.Text)
  			break
  		}
  	}
  }
  ```

  ```java Java
  import com.anthropic.config.AuthenticationConfig;
  import com.anthropic.config.AuthenticationType;
  import com.anthropic.config.IdentityTokenConfig;
  import com.anthropic.config.InMemoryProfileConfigProvider;
  import com.anthropic.config.ProfileConfig;
  // ...
  import com.fasterxml.jackson.databind.ObjectMapper;
  import java.net.URI;
  import java.net.URLEncoder;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.util.Map;
  import java.util.stream.Collectors;
  import static java.nio.charset.StandardCharsets.UTF_8;

  void main() throws Exception {
      var form = Map.of(
                      "client_id", System.getenv("AZURE_CLIENT_ID"),
                      "grant_type", "client_credentials",
                      "scope", "api://<APP_ID>/.default",
                      "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      "client_assertion", Files.readString(Path.of(System.getenv("AZURE_FEDERATED_TOKEN_FILE"))))
              .entrySet().stream()
              .map(entry -> entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), UTF_8))
              .collect(Collectors.joining("&"));
      var request = HttpRequest.newBuilder(URI.create(
                      "https://login.microsoftonline.com/" + System.getenv("AZURE_TENANT_ID") + "/oauth2/v2.0/token"))
              .header("content-type", "application/x-www-form-urlencoded")
              .POST(HttpRequest.BodyPublishers.ofString(form))
              .build();

      // Java SDK は関数ではなく、トークン自体またはファイルパスを受け取ります。
      // source("value") の場合、path(...) がトークンを保持します。SDK は同じトークンを
      // Anthropic アクセストークンの更新のたびに送信するため、トークンが
      // 期限切れになるか、jti クレームがある場合は使用済みになると失敗します。長時間実行される
      // プロセスでは、source("file") を渡し、各更新の前に新しいトークンを
      // ファイルに書き込んでください。
      var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
      String entraToken = new ObjectMapper().readTree(response.body()).get("access_token").asText();

      AnthropicClient client = AnthropicOkHttpClient.builder()
              .configurationProvider(InMemoryProfileConfigProvider.of(ProfileConfig.builder()
                      .organizationId(System.getenv("ANTHROPIC_ORGANIZATION_ID"))
                      .workspaceId(System.getenv("ANTHROPIC_WORKSPACE_ID"))
                      .authentication(AuthenticationConfig.builder()
                              .type(AuthenticationType.OIDC_FEDERATION)
                              .federationRuleId(System.getenv("ANTHROPIC_FEDERATION_RULE_ID"))
                              .serviceAccountId(System.getenv("ANTHROPIC_SERVICE_ACCOUNT_ID"))
                              .identityToken(IdentityTokenConfig.builder()
                                      .source("value")
                                      .path(entraToken)
                                      .build())
                              .build())
                      .build()))
              .build();

      var message = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024)
              .addUserMessage("Hello from Azure")
              .build());

      IO.println(message.content());
  }
  ```

  ```csharp C#
  using Anthropic.Credentials;
  // ...

  var credentials = new WorkloadIdentityCredentials(new WorkloadIdentityOptions
  {
      FederationRuleId = Environment.GetEnvironmentVariable("ANTHROPIC_FEDERATION_RULE_ID")!,
      OrganizationId = Environment.GetEnvironmentVariable("ANTHROPIC_ORGANIZATION_ID"),
      ServiceAccountId = Environment.GetEnvironmentVariable("ANTHROPIC_SERVICE_ACCOUNT_ID"),
      WorkspaceId = Environment.GetEnvironmentVariable("ANTHROPIC_WORKSPACE_ID"),
      IdentityTokenProvider = new EntraFederationTokenProvider(),
  });
  using var client = new AnthropicClient(new ClientOptions { Credentials = credentials });

  var message = await client.Messages.Create(new()
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [new() { Role = Role.User, Content = "Hello from Azure" }],
  });
  foreach (var block in message.Content)
  {
      if (block.Value is TextBlock textBlock)
      {
          Console.WriteLine(textBlock.Text);
      }
  }

  class EntraFederationTokenProvider : IIdentityTokenProvider
  {
      private static readonly HttpClient Http = new();

      public async Task<string> GetIdentityTokenAsync(CancellationToken ct = default)
      {
          var federatedToken = await File.ReadAllTextAsync(
              Environment.GetEnvironmentVariable("AZURE_FEDERATED_TOKEN_FILE")!, ct);
          var tenantId = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
          var form = new FormUrlEncodedContent(new Dictionary<string, string>
          {
              ["client_id"] = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID")!,
              ["grant_type"] = "client_credentials",
              ["scope"] = "api://<APP_ID>/.default",
              ["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
              ["client_assertion"] = federatedToken,
          });
          var response = await Http.PostAsync(
              $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token", form, ct);
          response.EnsureSuccessStatusCode();
          using var json = await JsonDocument.ParseAsync(
              await response.Content.ReadAsStreamAsync(ct), default, ct);
          return json.RootElement.GetProperty("access_token").GetString()!;
      }
  }
  ```

  ```php PHP
  use Anthropic\Client;
  use Anthropic\Lib\Credentials\CredentialResult;
  use Anthropic\Lib\Credentials\IdentityTokenProvider;
  use Anthropic\Lib\Credentials\TokenCache;
  use Anthropic\Lib\Credentials\WorkloadIdentityCredentials;

  class EntraIdentityTokenViaFederation implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          $ch = curl_init('https://login.microsoftonline.com/' . getenv('AZURE_TENANT_ID') . '/oauth2/v2.0/token');
          curl_setopt_array($ch, [
              CURLOPT_RETURNTRANSFER => true,
              CURLOPT_POSTFIELDS => http_build_query([
                  'client_id' => getenv('AZURE_CLIENT_ID'),
                  'grant_type' => 'client_credentials',
                  'scope' => 'api://<APP_ID>/.default',
                  'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
                  'client_assertion' => file_get_contents(getenv('AZURE_FEDERATED_TOKEN_FILE')),
              ]),
          ]);
          $body = json_decode(curl_exec($ch), true);
          curl_close($ch);
          return $body['access_token'];
      }
  }

  $client = new Client(
      credentials: new CredentialResult(
          provider: new TokenCache(new WorkloadIdentityCredentials(
              identityProvider: new EntraIdentityTokenViaFederation(),
              federationRuleId: getenv('ANTHROPIC_FEDERATION_RULE_ID'),
              organizationId: getenv('ANTHROPIC_ORGANIZATION_ID'),
              serviceAccountId: getenv('ANTHROPIC_SERVICE_ACCOUNT_ID'),
              workspaceId: getenv('ANTHROPIC_WORKSPACE_ID') ?: null,
          )),
      ),
  );

  $message = $client->messages->create(
      model: 'claude-opus-5-5',
      maxTokens: 1024,
      messages: [['role' => 'user', 'content' => 'Hello from Azure']],
  );
  $textBlock = array_find($message->content, static fn ($block): bool => $block->type === 'text');
  echo $textBlock->text, PHP_EOL;
  ```

  ```ruby Ruby
  require "anthropic"
  require "json"
  require "net/http"

  def fetch_entra_token_via_federation
    tenant_id = ENV.fetch("AZURE_TENANT_ID")
    federated_token = File.read(ENV.fetch("AZURE_FEDERATED_TOKEN_FILE"))
    response = Net::HTTP.post_form(
      URI("https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/token"),
      "client_id" => ENV.fetch("AZURE_CLIENT_ID"),
      "grant_type" => "client_credentials",
      "scope" => "api://<APP_ID>/.default",
      "client_assertion_type" => "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
      "client_assertion" => federated_token
    )
    JSON.parse(response.body).fetch("access_token")
  end

  client = Anthropic::Client.new(
    credentials: Anthropic::WorkloadIdentityCredentials.new(
      identity_token_provider: -> { fetch_entra_token_via_federation },
      federation_rule_id: ENV.fetch("ANTHROPIC_FEDERATION_RULE_ID"),
      organization_id: ENV.fetch("ANTHROPIC_ORGANIZATION_ID"),
      service_account_id: ENV.fetch("ANTHROPIC_SERVICE_ACCOUNT_ID"),
      workspace_id: ENV["ANTHROPIC_WORKSPACE_ID"]
    )
  )

  message = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [{role: "user", content: "Hello from Azure"}]
  )
  puts message.content.find { it.type == :text }.text
  ```

  ```bash CLI
  # 1. Kubernetes が投影したトークンを Entra 発行のアクセス
  # トークンと交換し、CLI が読み取れる一時ファイルに書き込みます。
  ANTHROPIC_IDENTITY_TOKEN_FILE=$(mktemp)
  trap 'rm -f "$ANTHROPIC_IDENTITY_TOKEN_FILE"' EXIT
  curl -sS "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \
    -d client_id="$AZURE_CLIENT_ID" \
    -d grant_type=client_credentials \
    --data-urlencode "scope=api://<APP_ID>/.default" \
    -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
    --data-urlencode client_assertion@"$AZURE_FEDERATED_TOKEN_FILE" \
    | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
  export ANTHROPIC_IDENTITY_TOKEN_FILE

  # 2. Claude API を呼び出します。ANTHROPIC_FEDERATION_RULE_ID、
  # ANTHROPIC_ORGANIZATION_ID、ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID は
  # 環境変数から読み取られます。
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### セットアップを検証する

ラベル付きポッドの内部から、[トークンを取得して使用する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#acquire-and-use-the-token-2)に示した cURL による交換を実行し、`POST /v1/oauth/token` が `200` を返し、`sk-ant-oat01-` で始まる `access_token` と秒単位の `expires_in` 値が含まれていることを確認します。交換が不透明な `401` `authentication_error` レスポンス（メッセージ `Authentication failed`）で失敗した場合は、Claude Console の[認証履歴ページ](https://platform.claude.com/settings/workload-identity-federation?tab=history)で拒否理由を確認し、ステップ 1 の Entra 発行トークンをデコードして（コマンドは[失敗した交換のトラブルシューティング](https://platform.claude.com/docs/ja/manage-claude/wif-reference#troubleshoot-a-failed-exchange)を参照）、Azure 側で最も一般的な原因を確認してください。

* **発行者の不一致:** 登録した `issuer_url` はトークンの `iss` クレームと完全に一致する必要があります。v2.0 トークンには `https://login.microsoftonline.com/<TENANT_ID>/v2.0` が含まれます。デコードした `ver` クレームが `1.0` の場合は、[トークンが v1.0 の場合](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0)を参照してください。
* **トークンの有効期間:** テナントのトークン有効期間ポリシーまたは CAE によって `client_credentials` トークンが 7500 秒を超えて延長される場合は、[Anthropic を構成する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#configure-anthropic-2)で説明したように発行者の `max_jwt_lifetime_seconds` を引き上げてください。
* **オーディエンスの不一致:** ルールの `audience` はトークンの `aud` と完全に一致する必要があります。本ガイドで構成する v2.0 トークンの場合は、オーディエンスアプリ登録のクライアント ID です。
* **クレーム名の不一致:** トークンに含まれないクレームに照合するルールは決して通過しません。v1.0 トークンはクライアント ID を `azp` ではなく `appid` に格納します。[トークンが v1.0 の場合](https://platform.claude.com/docs/ja/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0)を参照してください。

## トークンが v1.0 の場合

本ガイドはオーディエンスアプリ登録を `api.requestedAccessTokenVersion: 2` で構成するため、示されるトークンはすべて v2.0 です。`requestedAccessTokenVersion` が未設定のままの既存の登録を再利用する場合、Entra は代わりに v1.0 トークンを発行します。サンプルトークンをデコードして `ver` クレームを確認してください。`1.0` の場合、次の 4 点が変わります。

* **発行者:** `iss` クレームは `https://login.microsoftonline.com/<TENANT_ID>/v2.0` ではなく `https://sts.windows.net/<TENANT_ID>/` になります。発行者 URL は、トークンの `iss` クレームに含まれるとおり正確に登録してください。2 つの URL は同じ JWKS を共有しているため、ディスカバリーモードはどちらでも機能します。
* **ウィザードのセレクター:** Connect workload ウィザードの **Token issuer** セレクターで、**v2.0 (login.microsoftonline.com)** ではなく **v1 (sts.windows.net)** を選択します。
* **オーディエンス:** `aud` クレームは、登録のクライアント ID ではなく、`resource` として渡した識別子 URI（例: `api://<APP_ID>`）になります。フェデレーションルールの `audience` には、デコードしたトークンの `aud` 値をそのまま設定してください。
* **クライアント ID クレーム:** 呼び出し元 ID のクライアント ID は `azp` ではなく `appid` に現れます。この 2 つのクレームが同じトークンに同時に現れることはないため、`azp` に照合するルールは v1.0 トークンに対して決して通過しません。

`oid`、`sub`、`tid` クレームはどちらのバージョンでも同じ値を持つため、本ガイドの残りの部分はそのまま適用されます。

## ルールのスコープを絞る

フェデレーションルールは、`claims` マップに加えて（またはその代わりに）`subject_prefix` でトークンのサブジェクトに照合できます。フィールドの組み合わせ方については[ルール照合のセマンティクス](https://platform.claude.com/docs/ja/manage-claude/wif-reference#rule-matching-semantics)を参照してください。これらの ID に対する Entra の `sub` 値は固定長の正規 GUID であるため、36 文字のオブジェクト ID 全体を含む `subject_prefix` はそのサブジェクトにのみ一致します。これは Entra のサブジェクト形式の特性であり、`subject_prefix` 一般の特性ではありません。

<Warning>
  テナント内のすべての ID が登録済みオーディエンス向けのトークンを要求できるため、 `audience` と `tid` だけでは特定のワークロードを識別できません。`oid` （または `azp`/`appid`）の照合を省略したルール、あるいはワイルドカードや 部分的な GUID の `subject_prefix` を使用するルールは、テナント内のすべての マネージド ID とサービスプリンシパルを認可してしまいます。
</Warning>

ルールの `match` ブロックは、ユースケースに適合する最も狭いスコープに固定してください。

* **`oid` を完全な値として照合する:** `claims.oid` にマネージド ID の完全なオブジェクト ID を設定します。その完全なオブジェクト ID を設定した `subject_prefix` も同等です（Console のウィザードは両方を設定します）。意図したよりも多くの ID に一致してしまうワイルドカードや部分的な GUID の `subject_prefix` は決して使用しないでください。
* **多層防御として `tid` を固定する:** 発行者 URL がすでにテナントを固定していますが、`claims.tid` を追加することで、後で発行者レコードが編集された場合の構成ドリフトを防げます。
* **オーディエンスを固定する:** `audience` にデコードしたトークンの `aud` 値をそのまま設定し、他のアプリケーション向けに発行されたトークンが拒否されるようにします。
* **マネージド ID ごとに個別のルールを使用する:** 複数の ID を認可する 1 つのルールではなく、ID ごとに 1 つのルールを作成してください。そうすることで、他に影響を与えずに単一のワークロードのアクセスを取り消せます。

## 次のステップ

* [Workload Identity Federation](https://platform.claude.com/docs/ja/manage-claude/workload-identity-federation) で構成モデルの全体を確認してください。
* AWS、Google Cloud、GitHub Actions、Kubernetes については[プロバイダーガイド](https://platform.claude.com/docs/ja/manage-claude/workload-identity-federation#identity-providers)を参照してください。
* 環境変数、プロファイルファイル、資格情報の優先順位については、[WIF リファレンス](https://platform.claude.com/docs/ja/manage-claude/wif-reference)を参照してください。
