---
title: Использование WIF с Microsoft Entra ID
url: https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure
description: Настройте федерацию управляемых удостоверений Azure и Entra Workload Identity с Claude API, чтобы ваши рабочие нагрузки Azure могли вызывать Claude без статических ключей API.
---

Рабочие нагрузки Azure проходят аутентификацию в Claude API, предъявляя «JSON Web Token» (веб-токен JSON), или JWT, выпущенный Microsoft Entra ID, а затем обменивая его на краткосрочный токен доступа Anthropic. Настройка имеет одинаковую структуру на каждой платформе Azure:

1. **Зарегистрируйте аудиторию токена:** Создайте одну регистрацию приложения в вашем клиенте (tenant) Microsoft Entra, представляющую аудиторию Claude API. Каждая рабочая нагрузка в клиенте запрашивает токены Entra для неё.
2. **Настройте удостоверение для вашей платформы:** «Managed identity» (управляемое удостоверение) на виртуальных машинах, масштабируемых наборах виртуальных машин (VM Scale Sets), App Service, Functions и Container Apps либо Entra Workload Identity на AKS.
3. **Настройте Anthropic:** Зарегистрируйте издателя Entra вашего клиента, создайте сервисный аккаунт и напишите правило федерации, соответствующее утверждениям (claims) токена.
4. **Выполните обмен во время выполнения:** Ваша рабочая нагрузка обменивает выпущенный Entra токен через `POST /v1/oauth/token` на токен доступа Anthropic вида `sk-ant-oat01-...` и вызывает Claude с его помощью.

В обоих вариантах токен, который вы предъявляете Anthropic, содержит специфичного для вашего клиента издателя Entra и идентификатор объекта управляемого удостоверения в утверждениях `sub` и `oid`; различается только способ получения этого токена рабочей нагрузкой. Выберите раздел в зависимости от того, где выполняется ваша рабочая нагрузка: [Использование управляемого удостоверения](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#use-a-managed-identity) для виртуальных машин, VM Scale Sets, App Service, Functions или Container Apps; [Использование Entra Workload Identity на AKS](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#use-entra-workload-identity-on-aks) для AKS.

## Предварительные требования

* Знакомство с [концепциями WIF](https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation#concepts): сервисные аккаунты, издатели федерации и правила федерации.
* Подписка Azure с разрешением назначать управляемые удостоверения (или настраивать Entra Workload Identity на AKS).
* Разрешение на создание одной регистрации приложения и субъекта-службы (service principal) в вашем клиенте Microsoft Entra (общая аудитория Claude API). Entra выпускает токены только для аудитории, существующей в клиенте, поэтому шаг [Регистрация аудитории токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#register-the-token-audience) обязателен, прежде чем любой запрос токена завершится успешно.
* Идентификатор вашего клиента Microsoft Entra. Найдите его на портале Azure в разделе **Microsoft Entra ID → Overview → Tenant ID**.
* Разрешение на создание сервисных аккаунтов, издателей федерации и правил федерации в Claude Console для вашей организации Anthropic.

## Регистрация аудитории токена

Microsoft Entra ID выпускает токен только тогда, когда запрошенная аудитория существует в вашем клиенте в виде регистрации приложения с субъектом-службой. Создайте одну регистрацию приложения, представляющую аудиторию Claude API; каждая рабочая нагрузка в клиенте может запрашивать токены для неё. Без этой регистрации запросы токенов завершаются ошибкой «resource not found in tenant» (`AADSTS50001` от конечных точек управляемого удостоверения, `AADSTS500011` от конечной точки токенов Entra).

```bash
# Создайте регистрацию приложения, представляющую аудиторию Claude API.
APP_ID=$(az ad app create --display-name claude-api-federation --query appId -o tsv)

# Запросите токены доступа v2.0 и задайте URI идентификатора api://<APP_ID>.
az ad app update --id "$APP_ID" \
  --identifier-uris "api://$APP_ID" \
  --set api.requestedAccessTokenVersion=2

# Создайте субъект-службу, чтобы аудитория разрешалась в вашем клиенте.
az ad sp create --id "$APP_ID"
```

<Note>
  Используйте формат URI идентификатора `api://<APP_ID>`. Entra ограничивает URI идентификаторов вида `https://` проверенными доменами вашего собственного клиента, поэтому URI, такой как `https://api.anthropic.com`, невозможно зарегистрировать в большинстве клиентов; `api://<APP_ID>` принимается везде. При `requestedAccessTokenVersion: 2` токены для этой аудитории имеют версию v2.0, что и предполагается в данном руководстве. Если вы повторно используете существующую регистрацию, выпускающую токены v1.0, см. раздел [Если ваши токены версии v1.0](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
</Note>

## Использование управляемого удостоверения

Используйте этот вариант, если ваша рабочая нагрузка выполняется на виртуальной машине, в VM Scale Set, App Service, Functions или Container Apps. Рабочая нагрузка запрашивает выпущенный Entra JWT для назначенного ей управляемого удостоверения у локальной конечной точки токенов платформы, а затем обменивает этот JWT у Anthropic.

### Настройка управляемого удостоверения

<Steps>
  <Step title="Подключите управляемое удостоверение">
    Включите назначаемое системой или назначаемое пользователем управляемое удостоверение на вашем ресурсе Azure. На портале Azure откройте ресурс, перейдите в раздел **Identity** и включите **System assigned** (или подключите назначаемое пользователем удостоверение).

    После создания удостоверения запишите его **Object (principal) ID**. Этот GUID присутствует в выпущенном токене одновременно в утверждениях `sub` и `oid`, и ваше правило федерации Anthropic будет сопоставляться по нему. Вы можете найти его на странице **Identity** ресурса; для назначаемого пользователем удостоверения это **Object (principal) ID** на странице **Overview** ресурса управляемого удостоверения. (Управляемое удостоверение имеет в Microsoft Entra ID только субъект-службу, а не регистрацию приложения.)
  </Step>

  <Step title="Найдите конечную точку токенов платформы">
    После подключения удостоверения платформа предоставляет локальную конечную точку токенов:

    * **Виртуальные машины и 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:** URL из переменной окружения `IDENTITY_ENDPOINT` с заголовком `X-IDENTITY-HEADER`, установленным в значение `IDENTITY_HEADER`, и `api-version=2019-08-01`. IMDS недоступен на этих платформах.

    Если у ресурса более одного назначаемого пользователем управляемого удостоверения, добавьте `client_id=<IDENTITY_CLIENT_ID>` в запрос токена, чтобы выбрать одно из них. Azure рекомендует всегда указывать его. Без него результат зависит от того, включено ли на ресурсе также назначаемое системой удостоверение: если да, запрос незаметно переключается на это удостоверение и затем не проходит сопоставление по `oid` в вашем правиле федерации; если нет, запрос сразу завершается ошибкой, как только подключается второе назначаемое пользователем удостоверение.
  </Step>

  <Step title="Декодируйте пример токена">
    Запросите токен у конечной точки и декодируйте его полезную нагрузку, чтобы подтвердить утверждения, по которым должно сопоставляться ваше правило федерации. (Команду декодирования см. в разделе [Устранение неполадок при неудачном обмене](https://platform.claude.com/docs/ru/manage-claude/wif-reference#troubleshoot-a-failed-exchange).) Токен 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`       | Идентификатор объекта управляемого удостоверения, идентичный `sub`                                                                                                                                                    | Вы хотите авторизовать одно конкретное управляемое удостоверение. Это вариант по умолчанию; правило в разделе [Настройка Anthropic](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#configure-anthropic) сопоставляется по нему. |
    | `azp`       | Идентификатор клиента (client ID) вызывающего удостоверения                                                                                                                                                           | Вы хотите авторизовать каждую рабочую нагрузку, использующую одну общую регистрацию приложения. Для управляемого удостоверения `azp` уникален для этого удостоверения, поэтому он эквивалентен `oid`.                                                  |
    | `aud`       | Идентификатор клиента регистрации приложения аудитории (GUID `<APP_ID>` из раздела [Регистрация аудитории токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#register-the-token-audience)) | Всегда. Поле `audience` правила должно точно совпадать со значением `aud` токена.                                                                                                                                                                      |
    | `tid`       | Идентификатор вашего клиента                                                                                                                                                                                          | Вы хотите эшелонированную защиту. URL издателя уже фиксирует клиента.                                                                                                                                                                                  |

    Если утверждение `ver` декодированного токена равно `1.0`, имена и значения утверждений отличаются. Прежде чем продолжить, см. раздел [Если ваши токены версии v1.0](https://platform.claude.com/docs/ru/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/ru/manage-claude/wif-admin-api):

**Издатель федерации:** Выберите **v2.0 (login.microsoftonline.com)** в селекторе **Token issuer** мастера. (По умолчанию в селекторе выбрано v1; это значение по умолчанию существует для клиентов, повторно использующих старые регистрации, которые всё ещё выпускают токены v1.0.) Entra публикует документ обнаружения OIDC по URL издателя для каждого клиента, поэтому используйте режим обнаружения. Каждому клиенту 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>
  Рабочим нагрузкам с управляемым удостоверением требуется `max_jwt_lifetime_seconds: 86400`. Azure выдаёт токены управляемых удостоверений с интервалом до 24 часов между `iat` и `exp`, поскольку кэширует токен каждого ресурса на этот период и не предоставляет способа принудительно обновить его раньше, а значение издателя по умолчанию в 1 час отклоняет такие токены, поэтому обмен завершается непрозрачным ответом `401` `authentication_error` (сообщение `Authentication failed`). Плитка Microsoft Entra мастера Connect workload создаёт издателя с `max_jwt_lifetime_seconds`, равным `7500`, и не предоставляет поля для изменения этого значения при создании, поэтому завершите работу мастера, затем откройте вкладку **Issuers** на странице [Workload identity](https://platform.claude.com/settings/workload-identity-federation) в Claude Console, отредактируйте издателя и увеличьте значение до `86400`. Вы также можете обновить издателя через Admin API.
</Warning>

Более длительный допустимый срок действия означает, что утёкший токен Entra дольше остаётся пригодным для обмена. Если токен утёк, рычагом воздействия является отключение правила федерации; строгое сопоставление по `oid` изначально ограничивает, какие удостоверения могут обменять токен, как описано в разделе [Ограничение области действия правила](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#scope-your-rule).

**Правило федерации:** Сопоставляйте по идентификатору объекта управляемого удостоверения и идентификатору вашего клиента. Для токенов v2.0, настраиваемых в этом руководстве, значением `audience` является идентификатор клиента регистрации приложения аудитории (GUID `<APP_ID>` из раздела [Регистрация аудитории токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#register-the-token-audience)). Используйте точное значение `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. Claude SDK берёт на себя цикл обмена и обновления, когда вы передаёте `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), как показано в следующих примерах. За исключением Java (см. комментарий в этом примере), этот параметр принимает поставщика токенов, и SDK вызывает его снова при каждом обновлении. На вкладке cURL показан процесс без SDK.

Примеры получают токен управляемого удостоверения от конечной точки токенов платформы: IMDS на виртуальных машинах и VM Scale Sets или службы `IDENTITY_ENDPOINT` в App Service, Functions и Container Apps. Замените `<APP_ID>` в значении ресурса `api://<APP_ID>` на идентификатор клиента регистрации приложения аудитории из раздела [Регистрация аудитории токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#register-the-token-audience).

<Tip>
  Если ваша рабочая нагрузка уже использует клиентскую библиотеку Azure Identity, получайте токен Entra из неё (`DefaultAzureCredential` с областью `api://<APP_ID>/.default`) вместо прямого вызова конечных точек токенов. Передайте его в `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) так же, как это делается в примерах. Библиотека выбирает правильную конечную точку на любой платформе Azure, включая AKS с Entra Workload Identity.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Получите токен, выданный Entra (управляемое удостоверение).
  #    На VM или VM Scale Set используйте IMDS. При нескольких назначаемых пользователем
  #    удостоверениях добавьте &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)

  #    Для AKS с Entra Workload Identity используйте вместо этого двухэтапный обмен из
  #    раздела «Use Entra Workload Identity on AKS».

  # 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 с bearer-токеном.
  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."""
      # При нескольких назначаемых пользователем удостоверениях добавьте client_id=<IDENTITY_CLIENT_ID>
      # в параметры запроса, чтобы выбрать одно из них.
      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:
          # ВМ или масштабируемый набор ВМ: 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.
    // При нескольких назначаемых пользователем удостоверениях добавьте &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 получает токен управляемого удостоверения из конечной точки токенов
  // платформы: IMDS на VM и VM Scale Sets или служба IDENTITY_ENDPOINT
  // в App Service, Functions и Container Apps.
  func fetchEntraToken(ctx context.Context) (string, error) {
  	// При нескольких назначаемых пользователем удостоверениях добавьте &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.
      // При нескольких назначаемых пользователем удостоверениях добавьте &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.
          // При нескольких назначаемых пользователем удостоверениях добавьте &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.
          // При нескольких назначаемых пользователем удостоверениях добавьте &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 Scale Sets используют IMDS.
    # При нескольких назначаемых пользователем удостоверениях добавьте &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".
  # При нескольких назначаемых пользователем удостоверениях добавьте &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 выполните обмен через cURL, показанный в разделе [Получение и использование токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#acquire-and-use-the-token), и убедитесь, что `POST /v1/oauth/token` возвращает `200` с `access_token`, начинающимся с `sk-ant-oat01-`, и значением `expires_in` в секундах. Если обмен завершается непрозрачным ответом `401` `authentication_error` (сообщение `Authentication failed`), проверьте причину отказа на [странице истории аутентификации](https://platform.claude.com/settings/workload-identity-federation?tab=history) в Claude Console, затем декодируйте токен Entra (команду см. в разделе [Устранение неполадок при неудачном обмене](https://platform.claude.com/docs/ru/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/ru/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Срок действия токена:** Токены управляемых удостоверений имеют интервал до 24 часов между `iat` и `exp`. Если у издателя всё ещё установлено значение мастера `7500` (или значение по умолчанию в 1 час), увеличьте `max_jwt_lifetime_seconds` до `86400`, как описано в разделе [Настройка Anthropic](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#configure-anthropic).
* **Несовпадение аудитории:** Значение `audience` правила должно точно совпадать с `aud` токена: идентификатор клиента регистрации приложения аудитории для токенов v2.0, настраиваемых в этом руководстве.
* **Несовпадение имени утверждения:** Правило, сопоставляющееся по утверждению, которого нет в токене, никогда не проходит. Токены v1.0 содержат идентификатор клиента в `appid`, а не в `azp`; см. раздел [Если ваши токены версии v1.0](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Использование Entra Workload Identity на AKS

Используйте этот вариант, если ваша рабочая нагрузка выполняется в поде AKS. Entra Workload Identity устанавливает федерацию между сервисным аккаунтом Kubernetes и назначаемым пользователем управляемым удостоверением: Kubernetes проецирует токен сервисного аккаунта (подписанный издателем OIDC кластера AKS) в под по пути, указанному в `AZURE_FEDERATED_TOKEN_FILE`. Этот проецируемый токен не является токеном, выпущенным Entra, поэтому, чтобы остаться на описанном на этой странице пути через Entra, рабочая нагрузка выполняет двухэтапный обмен: сначала она обменивает проецируемый токен по адресу `https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token` (федеративный грант `client_credentials`) на выпущенный Entra токен доступа, а затем передаёт этот токен Entra в SDK Anthropic в качестве токена удостоверения.

<Tip>
  В качестве альтернативы поды AKS могут пропустить обмен через Entra и предъявить Anthropic напрямую проецируемый Kubernetes токен сервисного аккаунта. В этом варианте в Anthropic регистрируется издатель OIDC вашего кластера AKS вместо вашего клиента Entra. Описание этого потока см. в разделе [Использование WIF с Kubernetes](https://platform.claude.com/docs/ru/manage-claude/wif-providers/kubernetes).
</Tip>

### Настройка Entra Workload Identity

<Steps>
  <Step title="Включите издателя OIDC и workload identity на вашем кластере">
    Включение workload identity устанавливает за вас мутирующий вебхук `azure-workload-identity`; разворачивайте его вручную только на кластерах, отличных от AKS. Сохраните URL издателя OIDC кластера для федеративных учётных данных, которые вы создадите на одном из следующих шагов.

    ```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="Создайте назначаемое пользователем управляемое удостоверение">
    Сохраните два значения из удостоверения: **Client ID** указывается в аннотации сервисного аккаунта (и внедряется в под как `AZURE_CLIENT_ID`), а **Object (principal) ID** присутствует в виде утверждения `oid`, по которому сопоставляется ваше правило федерации Anthropic.

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

    # Отображается как claim 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` считывает аннотацию `azure.workload.identity/client-id`, чтобы внедрить `AZURE_CLIENT_ID` в под; примеры в разделе [Получение и использование токена](https://platform.claude.com/docs/ru/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="Создайте федеративные учётные данные на управляемом удостоверении">
    Федеративные учётные данные доверяют издателю OIDC вашего кластера для этого конкретного сервисного аккаунта. Значение `--audience api://AzureADTokenExchange` — это фиксированная аудитория Entra для входящих токенов сервисных аккаунтов Kubernetes; оно не связано с аудиторией 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"` и выполняться от имени аннотированного сервисного аккаунта. Затем вебхук внедряет в под `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` и `AZURE_TENANT_ID`. Файл по пути `AZURE_FEDERATED_TOKEN_FILE` содержит проецируемый Kubernetes токен сервисного аккаунта, подписанный издателем OIDC кластера AKS.

    ```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, — это не проецируемый файл, а выпущенный Entra токен, возвращаемый обменом `client_credentials`. Изнутри помеченного пода выполните шаг 1 примера cURL из раздела [Получение и использование токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) и декодируйте результат. Он имеет ту же структуру утверждений, что и в варианте с управляемым удостоверением:

    ```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` — это идентификатор объекта управляемого удостоверения, `aud` — идентификатор клиента регистрации приложения аудитории, а `azp` — идентификатор клиента управляемого удостоверения (значение `AZURE_CLIENT_ID`). Срок действия отличается от варианта с управляемым удостоверением: токены `client_credentials` по умолчанию имеют случайный интервал от 60 до 90 минут между `iat` и `exp`, а не 24 часа.
  </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/ru/manage-claude/wif-admin-api):

**Издатель федерации:** Выберите **v2.0 (login.microsoftonline.com)** в селекторе **Token issuer** мастера. (По умолчанию в селекторе выбрано v1; это значение по умолчанию существует для клиентов, повторно использующих старые регистрации, которые всё ещё выпускают токены v1.0.) Entra публикует документ обнаружения OIDC по URL издателя для каждого клиента, поэтому используйте режим обнаружения. Каждому клиенту 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>
  Плитка Microsoft Entra мастера Connect workload создаёт издателя с `max_jwt_lifetime_seconds`, равным `7500` (чуть более 2 часов), что покрывает срок действия токенов `client_credentials` по умолчанию от 60 до 90 минут. Политика срока действия токенов клиента или «Continuous Access Evaluation» (непрерывная оценка доступа), или CAE, может продлить этот срок. Если разница `exp` минус `iat` вашего декодированного токена превышает 7500 секунд, отредактируйте издателя на вкладке **Issuers** страницы [Workload identity](https://platform.claude.com/settings/workload-identity-federation) в Claude Console и увеличьте `max_jwt_lifetime_seconds` соответствующим образом, иначе обмены будут завершаться непрозрачным ответом `401` `authentication_error` (сообщение `Authentication failed`). Если в вашем клиенте также выполняются рабочие нагрузки с управляемым удостоверением из раздела [Использование управляемого удостоверения](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#use-a-managed-identity), используйте значение `86400` из того раздела, которое покрывает оба варианта.
</Warning>

Более длительный допустимый срок действия означает, что утёкший токен Entra дольше остаётся пригодным для обмена. Если токен утёк, рычагом воздействия является отключение правила федерации; строгое сопоставление по `oid` изначально ограничивает, какие удостоверения могут обменять токен, как описано в разделе [Ограничение области действия правила](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#scope-your-rule).

**Правило федерации:** Сопоставляйте по идентификатору объекта управляемого удостоверения и идентификатору вашего клиента. Для токенов v2.0, настраиваемых в этом руководстве, значением `audience` является идентификатор клиента регистрации приложения аудитории (GUID `<APP_ID>` из раздела [Регистрация аудитории токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#register-the-token-audience)). Используйте точное значение `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 обновляет его за вас.

### Получение и использование токена

Во время выполнения под выполняет двухэтапный обмен: он отправляет проецируемый Kubernetes токен (файл по пути `AZURE_FEDERATED_TOKEN_FILE`) в конечную точку токенов Entra в качестве федеративного утверждения `client_credentials`, а затем обменивает полученный токен доступа Entra в `POST /v1/oauth/token`. Claude SDK берёт на себя второй обмен и цикл обновления, когда вы передаёте `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), как показано в следующих примерах. За исключением Java (см. комментарий в этом примере), этот параметр принимает вашу функцию получения токена Entra в качестве поставщика токенов, и SDK вызывает её снова при каждом обновлении. На вкладке cURL показан процесс без SDK.

В примерах встречаются два разных идентификатора клиента. `<APP_ID>` — это идентификатор клиента регистрации приложения аудитории из раздела [Регистрация аудитории токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#register-the-token-audience); область `api://<APP_ID>/.default` запрашивает у Entra токен, адресованный этой аудитории. `$AZURE_CLIENT_ID` — это идентификатор клиента управляемого удостоверения, внедрённый вебхуком; он идентифицирует вызывающую сторону. Не подставляйте один вместо другого.

<Tip>
  Если ваша рабочая нагрузка уже использует клиентскую библиотеку Azure Identity, получайте токен Entra из неё (`DefaultAzureCredential` с областью `api://<APP_ID>/.default`) вместо того, чтобы выполнять двухэтапный обмен самостоятельно. Передайте его в `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),
  #    на JWT, выданный Entra.
  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. Обменяйте JWT от Entra на токен доступа 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>

### Проверка настройки

Изнутри пода с меткой выполните обмен через cURL, показанный в разделе [Получение и использование токена](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#acquire-and-use-the-token-2), и убедитесь, что `POST /v1/oauth/token` возвращает `200` с `access_token`, начинающимся с `sk-ant-oat01-`, и значением `expires_in` в секундах. Если обмен завершается непрозрачным ответом `401` `authentication_error` (сообщение `Authentication failed`), проверьте причину отказа на [странице истории аутентификации](https://platform.claude.com/settings/workload-identity-federation?tab=history) в Claude Console, затем декодируйте выданный Entra токен из шага 1 (команду см. в разделе [Устранение неполадок при неудачном обмене](https://platform.claude.com/docs/ru/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/ru/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Срок действия токена:** Если политика срока действия токенов клиента или CAE продлевает токен `client_credentials` сверх 7500 секунд, увеличьте `max_jwt_lifetime_seconds` издателя, как описано в разделе [Настройка Anthropic](https://platform.claude.com/docs/ru/manage-claude/wif-providers/azure#configure-anthropic-2).
* **Несовпадение аудитории:** Значение `audience` правила должно точно совпадать с `aud` токена: идентификатор клиента регистрации приложения аудитории для токенов v2.0, настраиваемых в этом руководстве.
* **Несовпадение имени утверждения:** Правило, сопоставляющееся по утверждению, которого нет в токене, никогда не проходит. Токены v1.0 содержат идентификатор клиента в `appid`, а не в `azp`; см. раздел [Если ваши токены версии v1.0](https://platform.claude.com/docs/ru/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`, меняются четыре вещи:

* **Издатель:** Утверждение `iss` равно `https://sts.windows.net/<TENANT_ID>/` вместо `https://login.microsoftonline.com/<TENANT_ID>/v2.0`. Зарегистрируйте URL издателя точно в том виде, в каком он содержится в утверждении `iss` вашего токена. Оба URL используют один и тот же JWKS, поэтому режим обнаружения работает для любого из них.
* **Селектор мастера:** Выберите **v1 (sts.windows.net)** в селекторе **Token issuer** мастера Connect workload вместо **v2.0 (login.microsoftonline.com)**.
* **Аудитория:** Утверждение `aud` — это URI идентификатора, который вы передали как `resource` (например, `api://<APP_ID>`), а не идентификатор клиента регистрации. Установите `audience` правила федерации в точное значение `aud` из вашего декодированного токена.
* **Утверждение идентификатора клиента:** Идентификатор клиента вызывающего удостоверения присутствует в `appid`, а не в `azp`. Эти два утверждения никогда не встречаются в одном токене, поэтому правило, сопоставляющееся по `azp`, никогда не проходит для токена v1.0.

Утверждения `oid`, `sub` и `tid` содержат одинаковые значения в обеих версиях, поэтому остальная часть этого руководства применяется без изменений.

## Ограничение области действия правила

Правило федерации может сопоставлять субъект токена с помощью `subject_prefix` в дополнение к карте `claims` (или вместо неё); о том, как сочетаются поля, см. раздел [Семантика сопоставления правил](https://platform.claude.com/docs/ru/manage-claude/wif-reference#rule-matching-semantics). Значения `sub` в Entra для этих удостоверений — канонические GUID фиксированной длины, поэтому `subject_prefix`, содержащий полный 36-символьный идентификатор объекта, соответствует только этому субъекту; это свойство формата субъекта Entra, а не `subject_prefix` в целом.

<Warning>
  Каждое удостоверение в вашем клиенте может запросить токен для зарегистрированной аудитории, поэтому `audience` и `tid` сами по себе не идентифицируют конкретную рабочую нагрузку. Правило, в котором отсутствует сопоставление по `oid` (или `azp`/`appid`) либо используется подстановочный знак или `subject_prefix` с частичным GUID, авторизует каждое управляемое удостоверение и каждый субъект-службу в клиенте.
</Warning>

Ограничьте блок `match` правила самой узкой областью, подходящей для вашего сценария:

* **Сопоставляйте `oid` как точное значение:** Установите `claims.oid` в полный идентификатор объекта управляемого удостоверения. `subject_prefix`, установленный в этот полный идентификатор объекта, эквивалентен (мастер Console задаёт оба); никогда не используйте подстановочный знак или `subject_prefix` с частичным GUID, который соответствует большему числу удостоверений, чем вы предполагаете.
* **Зафиксируйте `tid` для эшелонированной защиты:** URL издателя уже фиксирует ваш клиент, но добавление `claims.tid` защищает от дрейфа конфигурации, если запись издателя будет позже отредактирована.
* **Зафиксируйте аудиторию:** Установите `audience` в точное значение `aud` из вашего декодированного токена, чтобы токены, выпущенные для других приложений, отклонялись.
* **Используйте отдельное правило для каждого управляемого удостоверения:** Создавайте по одному правилу для каждого удостоверения, а не одно правило, авторизующее несколько, чтобы вы могли отозвать доступ одной рабочей нагрузки, не затрагивая остальные.

## Следующие шаги

* Ознакомьтесь с полной моделью конфигурации в разделе [Workload Identity Federation](https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation).
* См. [руководства по провайдерам](https://platform.claude.com/docs/ru/manage-claude/workload-identity-federation#identity-providers) для AWS, Google Cloud, GitHub Actions и Kubernetes.
* О переменных окружения, файлах профилей и приоритете учётных данных см. [справочник по WIF](https://platform.claude.com/docs/ru/manage-claude/wif-reference).
