---
title: Usa WIF con Microsoft Entra ID
url: https://platform.claude.com/docs/es/manage-claude/wif-providers/azure
description: Federa las identidades administradas de Azure y Entra Workload Identity con la Claude API para que tus cargas de trabajo de Azure puedan llamar a Claude sin claves de API estáticas.
---

Las cargas de trabajo de Azure se autentican en la Claude API presentando un JSON Web Token (JWT) emitido por Microsoft Entra ID y luego intercambiándolo por un token de acceso de Anthropic de corta duración. La configuración sigue la misma forma en todas las plataformas de Azure:

1. **Registra la audiencia del token:** Crea un "app registration" (registro de aplicación) en tu "tenant" (inquilino) de Microsoft Entra para representar la audiencia de la Claude API. Todas las cargas de trabajo del inquilino solicitan tokens de Entra para él.
2. **Configura la identidad para tu plataforma:** Una "managed identity" (identidad administrada) en VMs, VM Scale Sets, App Service, Functions y Container Apps, o Entra Workload Identity en AKS.
3. **Configura Anthropic:** Registra el emisor de Entra de tu inquilino, crea una cuenta de servicio y escribe una regla de federación que coincida con los "claims" (notificaciones) del token.
4. **Intercambia en tiempo de ejecución:** Tu carga de trabajo intercambia su token emitido por Entra en `POST /v1/oauth/token` por un token de acceso de Anthropic `sk-ant-oat01-...` y llama a Claude con él.

En ambas rutas, el token que presentas a Anthropic lleva el emisor de Entra específico de tu inquilino y el ID de objeto de la identidad administrada en los claims `sub` y `oid`; solo difiere la forma en que la carga de trabajo obtiene ese token. Elige la sección correspondiente al lugar donde se ejecuta tu carga de trabajo: [Usa una identidad administrada](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#use-a-managed-identity) para VMs, VM Scale Sets, App Service, Functions o Container Apps; [Usa Entra Workload Identity en AKS](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#use-entra-workload-identity-on-aks) para AKS.

## Requisitos previos

* Familiaridad con los [conceptos de WIF](https://platform.claude.com/docs/es/manage-claude/workload-identity-federation#concepts): cuentas de servicio, emisores de federación y reglas de federación.
* Una suscripción de Azure con permiso para asignar identidades administradas (o configurar Entra Workload Identity en AKS).
* Permiso para crear un registro de aplicación y una "service principal" (entidad de servicio) en tu inquilino de Microsoft Entra (la audiencia compartida de la Claude API). Entra solo emite tokens para una audiencia que exista en el inquilino, por lo que el paso [Registra la audiencia del token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#register-the-token-audience) es obligatorio antes de que cualquier solicitud de token tenga éxito.
* El ID de tu inquilino de Microsoft Entra. Encuéntralo en el portal de Azure en **Microsoft Entra ID → Overview → Tenant ID**.
* Permiso para crear cuentas de servicio, emisores de federación y reglas de federación en la Claude Console para tu organización de Anthropic.

## Registra la audiencia del token

Microsoft Entra ID solo emite un token cuando la audiencia solicitada existe en tu inquilino como un registro de aplicación con una entidad de servicio. Crea un registro de aplicación para representar la audiencia de la Claude API; todas las cargas de trabajo del inquilino pueden solicitar tokens para él. Sin este registro, las solicitudes de token fallan con un error "resource not found in tenant" (`AADSTS50001` desde los endpoints de identidad administrada, `AADSTS500011` desde el endpoint de token de Entra).

```bash
# Crea el registro de aplicación que representa la audiencia de la Claude API.
APP_ID=$(az ad app create --display-name claude-api-federation --query appId -o tsv)

# Solicita tokens de acceso v2.0 y establece el URI identificador api://<APP_ID>.
az ad app update --id "$APP_ID" \
  --identifier-uris "api://$APP_ID" \
  --set api.requestedAccessTokenVersion=2

# Crea la entidad de servicio para que la audiencia se resuelva en tu inquilino.
az ad sp create --id "$APP_ID"
```

<Note>
  Usa el formato de URI de identificador `api://<APP_ID>`. Entra restringe los URI de identificador `https://` a dominios verificados de tu propio inquilino, por lo que un URI como `https://api.anthropic.com` no puede registrarse en la mayoría de los inquilinos; `api://<APP_ID>` se acepta en todas partes. Con `requestedAccessTokenVersion: 2`, los tokens para esta audiencia son v2.0, que es lo que esta guía asume. Si reutilizas un registro existente que emite tokens v1.0, consulta [Si tus tokens son v1.0](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
</Note>

## Usa una identidad administrada

Usa esta ruta cuando tu carga de trabajo se ejecuta en una VM, un VM Scale Set, App Service, Functions o Container Apps. La carga de trabajo solicita un JWT emitido por Entra para su identidad administrada asignada desde el endpoint de token local de la plataforma y luego intercambia ese JWT con Anthropic.

### Configura la identidad administrada

<Steps>
  <Step title="Adjunta una identidad administrada">
    Habilita una identidad administrada asignada por el sistema o asignada por el usuario en tu recurso de Azure. En el portal de Azure, abre el recurso, ve a **Identity** y activa **System assigned** (o adjunta una identidad asignada por el usuario).

    Una vez creada la identidad, anota su **Object (principal) ID**. Este GUID aparece tanto en el claim `sub` como en el claim `oid` del token emitido, y tu regla de federación de Anthropic coincidirá con él. Puedes encontrarlo en la página **Identity** del recurso; para una identidad asignada por el usuario, es el **Object (principal) ID** en la página **Overview** del recurso de identidad administrada. (Una identidad administrada solo tiene una entidad de servicio en Microsoft Entra ID, no un registro de aplicación).
  </Step>

  <Step title="Encuentra el endpoint de token de la plataforma">
    La plataforma expone un endpoint de token local una vez que la identidad está adjunta:

    * **VMs y VM Scale Sets:** IMDS en `http://169.254.169.254/metadata/identity/oauth2/token` con el encabezado `Metadata: true` y `api-version=2018-02-01`.
    * **App Service, Functions y Container Apps:** La URL en la variable de entorno `IDENTITY_ENDPOINT` con el encabezado `X-IDENTITY-HEADER` establecido en el valor de `IDENTITY_HEADER`, y `api-version=2019-08-01`. IMDS no es accesible en estas plataformas.

    Si el recurso tiene más de una identidad administrada asignada por el usuario, agrega `client_id=<IDENTITY_CLIENT_ID>` a la solicitud de token para seleccionar una. Azure recomienda especificarlo siempre. Sin él, el resultado depende de si el recurso también tiene habilitada una identidad asignada por el sistema: si la tiene, la solicitud recurre silenciosamente a esa identidad y luego falla la coincidencia de `oid` de tu regla de federación; si no la tiene, la solicitud falla directamente en cuanto se adjunta una segunda identidad asignada por el usuario.
  </Step>

  <Step title="Decodifica un token de muestra">
    Solicita un token al endpoint y decodifica su payload para confirmar los claims con los que tu regla de federación necesita coincidir. (Para el comando de decodificación, consulta [Soluciona un intercambio fallido](https://platform.claude.com/docs/es/manage-claude/wif-reference#troubleshoot-a-failed-exchange)). Un token v2.0 para una identidad administrada lleva estos claims:

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

    | Claim | Valor                                                                                                                                                                                                                 | Coincide con esto cuando                                                                                                                                                                                                                |
    | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `oid` | El ID de objeto de la identidad administrada, idéntico a `sub`                                                                                                                                                        | Quieres autorizar una identidad administrada específica. Este es el valor predeterminado; la regla en [Configura Anthropic](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#configure-anthropic) coincide con él. |
    | `azp` | El ID de cliente de la identidad que llama                                                                                                                                                                            | Quieres autorizar todas las cargas de trabajo que comparten un registro de aplicación. Para una identidad administrada, `azp` es único para esa identidad, por lo que es equivalente a `oid`.                                           |
    | `aud` | El ID de cliente del registro de aplicación de audiencia (el GUID `<APP_ID>` de [Registra la audiencia del token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#register-the-token-audience)) | Siempre. El campo `audience` de la regla debe ser exactamente igual al valor `aud` del token.                                                                                                                                           |
    | `tid` | El ID de tu inquilino                                                                                                                                                                                                 | Quieres defensa en profundidad. La URL del emisor ya fija el inquilino.                                                                                                                                                                 |

    Si el claim `ver` del token decodificado es `1.0`, los nombres y valores de los claims difieren. Consulta [Si tus tokens son v1.0](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0) antes de continuar.
  </Step>
</Steps>

### Configura Anthropic

En la Claude Console, ve a la página [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), haz clic en **Connect workload** y selecciona el mosaico **Microsoft Entra**. El asistente te guía para registrar el emisor, crear una cuenta de servicio y crear una regla de federación.

El asistente crea estos recursos por ti. Usa los siguientes valores, ya sea que los ingreses en el asistente o los envíes a la [Admin API](https://platform.claude.com/docs/es/manage-claude/wif-admin-api):

**Emisor de federación:** Elige **v2.0 (login.microsoftonline.com)** en el selector **Token issuer** del asistente. (El selector tiene v1 como valor predeterminado; ese valor predeterminado existe para inquilinos que reutilizan registros antiguos que aún emiten tokens v1.0). Entra publica un documento de descubrimiento OIDC en la URL del emisor por inquilino, así que usa el modo de descubrimiento. Cada inquilino de Microsoft Entra que federes necesita su propio registro de emisor.

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

<Warning>
  Las cargas de trabajo con identidad administrada necesitan `max_jwt_lifetime_seconds: 86400`. Azure emite tokens de identidad administrada con hasta 24 horas entre `iat` y `exp` porque almacena en caché el token de cada recurso durante ese período y no ofrece forma de forzar una actualización anticipada, y el valor predeterminado de 1 hora del emisor rechaza esos tokens, por lo que el intercambio falla con la respuesta opaca `401` `authentication_error` (mensaje `Authentication failed`). El mosaico Microsoft Entra del asistente Connect workload crea el emisor con `max_jwt_lifetime_seconds` establecido en `7500` y no proporciona ningún campo para cambiarlo durante la creación, así que termina el asistente, luego abre la pestaña **Issuers** en la página [Workload identity](https://platform.claude.com/settings/workload-identity-federation) de la Claude Console, edita el emisor y aumenta el valor a `86400`. También puedes actualizar el emisor mediante la Admin API.
</Warning>

Una vida útil aceptada más larga significa que un token de Entra filtrado sigue siendo intercambiable durante más tiempo. Si un token se filtra, la palanca es deshabilitar la regla de federación; una coincidencia estricta de `oid` limita qué identidades pueden intercambiar un token en primer lugar, como se describe en [Delimita tu regla](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#scope-your-rule).

**Regla de federación:** Haz coincidir el ID de objeto de la identidad administrada y el ID de tu inquilino. Para los tokens v2.0 que configura esta guía, el valor de `audience` es el ID de cliente del registro de aplicación de audiencia (el GUID `<APP_ID>` de [Registra la audiencia del token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#register-the-token-audience)). Usa el valor `aud` exacto de tu token decodificado.

```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` es la vida útil del token de acceso de Anthropic que devuelve el intercambio, no la del token de Entra; el SDK lo actualiza por ti.

### Adquiere y usa el token

En tiempo de ejecución, tu carga de trabajo obtiene su token de Entra, lo intercambia en `POST /v1/oauth/token` y usa el token bearer devuelto para llamar a Claude. El SDK de Claude gestiona el ciclo de intercambio y actualización cuando proporcionas `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), como se muestra en los siguientes ejemplos. Excepto en Java (consulta el comentario en ese ejemplo), esa opción recibe un proveedor de tokens, y el SDK lo vuelve a llamar en cada actualización. La pestaña cURL muestra el flujo sin procesar.

Los ejemplos obtienen el token de identidad administrada del endpoint de token de la plataforma: IMDS en VMs y VM Scale Sets, o el servicio `IDENTITY_ENDPOINT` en App Service, Functions y Container Apps. Reemplaza `<APP_ID>` en el valor de recurso `api://<APP_ID>` con el ID de cliente del registro de aplicación de audiencia de [Registra la audiencia del token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#register-the-token-audience).

<Tip>
  Si tu carga de trabajo ya usa la biblioteca cliente Azure Identity, obtén el token de Entra desde ella (`DefaultAzureCredential` con el scope `api://<APP_ID>/.default`) en lugar de llamar directamente a los endpoints de tokens. Proporciónalo a `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) como lo hacen los ejemplos. La biblioteca selecciona el endpoint correcto en todas las plataformas de Azure, incluido AKS con Entra Workload Identity.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Obtén el token emitido por Entra (identidad administrada).
  #    En una VM o un VM Scale Set, usa IMDS. Con varias identidades asignadas
  #    por el usuario, agrega &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)

  #    En App Service, Functions o Container Apps, usa en su lugar el servicio
  #    de tokens local (IMDS no es accesible allí):
  # 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)

  #    Para AKS con Entra Workload Identity, usa en su lugar el intercambio de dos saltos
  #    de la sección "Usar Entra Workload Identity en AKS".

  # 2. Intercámbialo por un token de acceso de 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. Llama a la API de Claude con el token de portador (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

  # El URI de identificador del registro de la aplicación de audiencia (consulta Registrar la audiencia del token).
  AUDIENCE = "api://<APP_ID>"


  def fetch_entra_token() -> str:
      """Fetch a managed identity token from the platform's token endpoint."""
      # Con varias identidades asignadas por el usuario, agrega client_id=<IDENTITY_CLIENT_ID>
      # a los parámetros de la solicitud para seleccionar una.
      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 o 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";

  // El URI de identificador del registro de la aplicación de audiencia (consulta Registrar la audiencia del token).
  const AUDIENCE = "api://<APP_ID>";

  async function fetchEntraToken(): Promise<string> {
    // App Service, Functions y Container Apps inyectan IDENTITY_ENDPOINT;
    // Las VM y los VM Scale Sets usan IMDS.
    // Con varias identidades asignadas por el usuario, agrega &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"
  )

  // El URI de identificador del registro de la app de audiencia (consulta Registrar la audiencia del token).
  const audience = "api://<APP_ID>"

  // fetchEntraToken obtiene un token de identidad administrada desde el endpoint de tokens
  // de la plataforma: IMDS en VMs y VM Scale Sets, o el servicio IDENTITY_ENDPOINT
  // en App Service, Functions y Container Apps.
  func fetchEntraToken(ctx context.Context) (string, error) {
  	// Con varias identidades asignadas por el usuario, agrega &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();
      // El URI de identificador del registro de la app de audiencia (consulta Registrar la audiencia del token).
      String audience = "api://<APP_ID>";
      // App Service, Functions y Container Apps inyectan IDENTITY_ENDPOINT;
      // Las VM y los VM Scale Sets usan IMDS.
      // Con varias identidades asignadas por el usuario, agrega &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();

      // El SDK de Java recibe el token en sí o una ruta de archivo, no una función; con
      // source("value"), path(...) contiene el token. El SDK envía ese mismo token
      // en cada actualización del token de acceso de Anthropic, lo cual falla una vez que
      // ha expirado o, si tiene un claim jti, ya se ha usado. Para un proceso de
      // mayor duración, pasa source("file") y escribe un token nuevo en el archivo antes de
      // cada actualización.
      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
  {
      // El URI de identificador del registro de la aplicación de audiencia (consulta Registrar la audiencia del token).
      private const string Audience = "api://<APP_ID>";

      private static readonly HttpClient httpClient = new();

      public async Task<string> GetIdentityTokenAsync(CancellationToken ct = default)
      {
          // App Service, Functions y Container Apps inyectan IDENTITY_ENDPOINT;
          // Las VM y los VM Scale Sets usan IMDS.
          // Con varias identidades asignadas por el usuario, agrega &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;

  // El URI de identificador del registro de la aplicación de audiencia (consulta Registrar la audiencia del token).
  const AUDIENCE = 'api://<APP_ID>';

  class EntraIdentityToken implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          // App Service, Functions y Container Apps inyectan IDENTITY_ENDPOINT;
          // Las VM y los VM Scale Sets usan IMDS.
          // Con varias identidades asignadas por el usuario, agrega &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"

  # El URI de identificador del registro de la aplicación de audiencia (consulta Registrar la audiencia del token).
  AUDIENCE = "api://<APP_ID>"

  def fetch_entra_token
    # App Service, Functions y Container Apps inyectan IDENTITY_ENDPOINT;
    # Las VM y los VM Scale Sets usan IMDS.
    # Con varias identidades asignadas por el usuario, agrega &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
  # Escribe el token de acceso emitido por Entra en un archivo que la CLI pueda leer.
  # Se muestra para una VM o un VM Scale Set (IMDS). En App Service, Functions o
  # Container Apps, obtenlo desde "$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=api://<APP_ID>"
  # con -H "X-IDENTITY-HEADER: $IDENTITY_HEADER" en su lugar.
  # Con varias identidades asignadas por el usuario, agrega &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 y ANTHROPIC_WORKSPACE_ID se leen del entorno.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### Verifica la configuración

Desde tu recurso de Azure, ejecuta el intercambio cURL que se muestra en [Adquiere y usa el token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#acquire-and-use-the-token) y confirma que `POST /v1/oauth/token` devuelve un `200` con un `access_token` que comienza con `sk-ant-oat01-` y un valor `expires_in` en segundos. Si el intercambio falla con la respuesta opaca `401` `authentication_error` (mensaje `Authentication failed`), revisa la [página del historial de autenticación](https://platform.claude.com/settings/workload-identity-federation?tab=history) en la Claude Console para ver el motivo de denegación, luego decodifica el token de Entra (consulta [Soluciona un intercambio fallido](https://platform.claude.com/docs/es/manage-claude/wif-reference#troubleshoot-a-failed-exchange) para ver el comando) y revisa las causas más comunes del lado de Azure:

* **Discrepancia de emisor:** El `issuer_url` registrado debe coincidir exactamente con el claim `iss` del token. Un token v2.0 lleva `https://login.microsoftonline.com/<TENANT_ID>/v2.0`; si el claim `ver` decodificado es `1.0`, consulta [Si tus tokens son v1.0](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Vida útil del token:** Los tokens de identidad administrada llevan hasta 24 horas entre `iat` y `exp`. Si el emisor aún tiene el `7500` del asistente (o el valor predeterminado de 1 hora), aumenta `max_jwt_lifetime_seconds` a `86400` como se describe en [Configura Anthropic](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#configure-anthropic).
* **Discrepancia de audiencia:** El `audience` de la regla debe ser exactamente igual al `aud` del token: el ID de cliente del registro de aplicación de audiencia para los tokens v2.0 que configura esta guía.
* **Discrepancia de nombre de claim:** Una regla que coincide con un claim que el token no lleva nunca pasa. Los tokens v1.0 llevan el ID de cliente en `appid`, no en `azp`; consulta [Si tus tokens son v1.0](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Usa Entra Workload Identity en AKS

Usa esta ruta cuando tu carga de trabajo se ejecuta en un pod de AKS. Entra Workload Identity federa una cuenta de servicio de Kubernetes con una identidad administrada asignada por el usuario: Kubernetes proyecta un token de cuenta de servicio (firmado por el emisor OIDC del clúster de AKS) en el pod en la ruta indicada en `AZURE_FEDERATED_TOKEN_FILE`. Ese token proyectado no es un token emitido por Entra, por lo que, para mantenerse en la ruta mediada por Entra descrita en esta página, la carga de trabajo realiza un intercambio de dos saltos: primero canjea el token proyectado en `https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token` (grant `client_credentials` federado) por un token de acceso emitido por Entra, y luego pasa ese token de Entra al SDK de Anthropic como token de identidad.

<Tip>
  Como alternativa, los pods de AKS pueden omitir el intercambio con Entra y presentar directamente a Anthropic el token de cuenta de servicio proyectado por Kubernetes. Esa ruta registra el emisor OIDC de tu clúster de AKS con Anthropic en lugar de tu inquilino de Entra. Consulta [Usa WIF con Kubernetes](https://platform.claude.com/docs/es/manage-claude/wif-providers/kubernetes) para ese flujo.
</Tip>

### Configura Entra Workload Identity

<Steps>
  <Step title="Habilita el emisor OIDC y workload identity en tu clúster">
    Habilitar workload identity instala el webhook de mutación `azure-workload-identity` por ti; despliégalo manualmente solo en clústeres que no sean AKS. Captura la URL del emisor OIDC del clúster para la credencial federada que crearás en un paso posterior.

    ```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="Crea una identidad administrada asignada por el usuario">
    Captura dos valores de la identidad: el **Client ID** va en la anotación de la cuenta de servicio (y se inyecta en el pod como `AZURE_CLIENT_ID`), y el **Object (principal) ID** aparece como el claim `oid` con el que coincide tu regla de federación de Anthropic.

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

    # Va en la anotación de la cuenta de servicio; se inyecta en el pod como AZURE_CLIENT_ID.
    IDENTITY_CLIENT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query clientId -o tsv)

    # Aparece como el claim oid con el que coincide tu regla de federación.
    IDENTITY_OBJECT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query principalId -o tsv)
    ```
  </Step>

  <Step title="Crea la cuenta de servicio de Kubernetes anotada">
    El webhook `azure-workload-identity` lee la anotación `azure.workload.identity/client-id` para inyectar `AZURE_CLIENT_ID` en el pod, que los ejemplos en [Adquiere y usa el token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) leen del entorno.

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

  <Step title="Crea la credencial federada en la identidad administrada">
    La credencial federada confía en el emisor OIDC de tu clúster para esa cuenta de servicio específica. El valor `--audience api://AzureADTokenExchange` es la audiencia fija de Entra para los tokens de cuenta de servicio de Kubernetes entrantes; no está relacionado con la audiencia de la Claude API que registraste anteriormente.

    ```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="Etiqueta el pod y establece su cuenta de servicio">
    El pod debe llevar la etiqueta `azure.workload.identity/use: "true"` y ejecutarse como la cuenta de servicio anotada. El webhook entonces inyecta `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` y `AZURE_TENANT_ID` en el pod. El archivo en `AZURE_FEDERATED_TOKEN_FILE` contiene el token de cuenta de servicio proyectado por Kubernetes, firmado por el emisor OIDC del clúster de 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="Decodifica un token de muestra">
    El token que ve tu regla de federación de Anthropic no es el archivo proyectado; es el token emitido por Entra que devuelve el intercambio `client_credentials`. Desde dentro de un pod etiquetado, ejecuta el paso 1 del ejemplo cURL en [Adquiere y usa el token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) y decodifica el resultado. Lleva la misma forma de claims que la ruta de identidad administrada:

    ```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` y `oid` son el ID de objeto de la identidad administrada, `aud` es el ID de cliente del registro de aplicación de audiencia y `azp` es el ID de cliente de la identidad administrada (el valor de `AZURE_CLIENT_ID`). La vida útil difiere de la ruta de identidad administrada: los tokens `client_credentials` tienen por defecto una ventana aleatoria de 60 a 90 minutos entre `iat` y `exp`, no 24 horas.
  </Step>
</Steps>

### Configura Anthropic

En la Claude Console, ve a la página [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), haz clic en **Connect workload** y selecciona el mosaico **Microsoft Entra**. El asistente te guía para registrar el emisor, crear una cuenta de servicio y crear una regla de federación.

El asistente crea estos recursos por ti. Usa los siguientes valores, ya sea que los ingreses en el asistente o los envíes a la [Admin API](https://platform.claude.com/docs/es/manage-claude/wif-admin-api):

**Emisor de federación:** Elige **v2.0 (login.microsoftonline.com)** en el selector **Token issuer** del asistente. (El selector tiene v1 como valor predeterminado; ese valor predeterminado existe para inquilinos que reutilizan registros antiguos que aún emiten tokens v1.0). Entra publica un documento de descubrimiento OIDC en la URL del emisor por inquilino, así que usa el modo de descubrimiento. Cada inquilino de Microsoft Entra que federes necesita su propio registro de emisor.

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

<Warning>
  El mosaico Microsoft Entra del asistente Connect workload crea el emisor con `max_jwt_lifetime_seconds` establecido en `7500` (poco más de 2 horas), lo que cubre la vida útil predeterminada de 60 a 90 minutos de los tokens `client_credentials`. Una política de vida útil de tokens del inquilino o Continuous Access Evaluation (CAE) puede extender esa vida útil. Si el `exp` menos `iat` de tu token decodificado supera los 7500 segundos, edita el emisor en la pestaña **Issuers** de la página [Workload identity](https://platform.claude.com/settings/workload-identity-federation) en la Claude Console y aumenta `max_jwt_lifetime_seconds` para que coincida; de lo contrario, los intercambios fallan con la respuesta opaca `401` `authentication_error` (mensaje `Authentication failed`). Si tu inquilino también ejecuta cargas de trabajo con identidad administrada de [Usa una identidad administrada](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#use-a-managed-identity), usa el valor `86400` de esa sección, que cubre ambas rutas.
</Warning>

Una vida útil aceptada más larga significa que un token de Entra filtrado sigue siendo intercambiable durante más tiempo. Si un token se filtra, la palanca es deshabilitar la regla de federación; una coincidencia estricta de `oid` limita qué identidades pueden intercambiar un token en primer lugar, como se describe en [Delimita tu regla](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#scope-your-rule).

**Regla de federación:** Haz coincidir el ID de objeto de la identidad administrada y el ID de tu inquilino. Para los tokens v2.0 que configura esta guía, el valor de `audience` es el ID de cliente del registro de aplicación de audiencia (el GUID `<APP_ID>` de [Registra la audiencia del token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#register-the-token-audience)). Usa el valor `aud` exacto de tu token decodificado.

```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` es la vida útil del token de acceso de Anthropic que devuelve el intercambio, no la del token de Entra; el SDK lo actualiza por ti.

### Adquiere y usa el token

En tiempo de ejecución, el pod realiza el intercambio de dos saltos: envía el token proyectado por Kubernetes (el archivo en `AZURE_FEDERATED_TOKEN_FILE`) al endpoint de tokens de Entra como una aserción `client_credentials` federada y luego intercambia el token de acceso de Entra resultante en `POST /v1/oauth/token`. El SDK de Claude gestiona el segundo intercambio y el ciclo de actualización cuando proporcionas `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), como se muestra en los siguientes ejemplos. Excepto en Java (consulta el comentario en ese ejemplo), esa opción recibe tu obtención del token de Entra como proveedor de tokens, y el SDK la vuelve a llamar en cada actualización. La pestaña cURL muestra el flujo sin procesar.

En los ejemplos aparecen dos ID de cliente diferentes. `<APP_ID>` es el ID de cliente del registro de aplicación de audiencia de [Registra la audiencia del token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#register-the-token-audience); el scope `api://<APP_ID>/.default` le pide a Entra un token dirigido a esa audiencia. `$AZURE_CLIENT_ID` es el ID de cliente de la identidad administrada, inyectado por el webhook, e identifica a quien llama. No sustituyas uno por el otro.

<Tip>
  Si tu carga de trabajo ya usa la biblioteca cliente Azure Identity, obtén el token de Entra desde ella (`DefaultAzureCredential` con el scope `api://<APP_ID>/.default`) en lugar de realizar tú mismo el intercambio en dos saltos. Proporciónalo a `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) como lo hacen los ejemplos. La biblioteca lee las mismas variables de entorno `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` y `AZURE_TENANT_ID` y gestiona el intercambio con Entra.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Intercambia el token proyectado por Kubernetes (en $AZURE_FEDERATED_TOKEN_FILE)
  #    por un JWT emitido por 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. Intercambia el JWT de Entra por un token de acceso de 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. Llama a la API de Claude.
  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();

      // El SDK de Java recibe el token en sí o una ruta de archivo, no una función; con
      // source("value"), path(...) contiene el token. El SDK envía ese mismo token
      // en cada actualización del token de acceso de Anthropic, lo cual falla una vez que ha
      // expirado o, si tiene un claim jti, ya se ha usado. Para un proceso de mayor duración,
      // pasa source("file") y escribe un token nuevo en el archivo antes de
      // cada actualización.
      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. Intercambia el token proyectado por Kubernetes por un token de acceso emitido por Entra
  # y escríbelo en un archivo temporal que la CLI pueda leer.
  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. Llama a la API de Claude. ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID se leen
  # del entorno.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### Verifica la configuración

Desde dentro de un pod etiquetado, ejecuta el intercambio cURL que se muestra en [Adquiere y usa el token](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) y confirma que `POST /v1/oauth/token` devuelve un `200` con un `access_token` que comienza con `sk-ant-oat01-` y un valor `expires_in` en segundos. Si el intercambio falla con la respuesta opaca `401` `authentication_error` (mensaje `Authentication failed`), revisa la [página del historial de autenticación](https://platform.claude.com/settings/workload-identity-federation?tab=history) en la Claude Console para ver el motivo de denegación, luego decodifica el token emitido por Entra del paso 1 (consulta [Soluciona un intercambio fallido](https://platform.claude.com/docs/es/manage-claude/wif-reference#troubleshoot-a-failed-exchange) para ver el comando) y revisa las causas más comunes del lado de Azure:

* **Discrepancia de emisor:** El `issuer_url` registrado debe coincidir exactamente con el claim `iss` del token. Un token v2.0 lleva `https://login.microsoftonline.com/<TENANT_ID>/v2.0`; si el claim `ver` decodificado es `1.0`, consulta [Si tus tokens son v1.0](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Vida útil del token:** Si una política de vida útil de tokens del inquilino o CAE extiende el token `client_credentials` más allá de 7500 segundos, aumenta el `max_jwt_lifetime_seconds` del emisor como se describe en [Configura Anthropic](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#configure-anthropic-2).
* **Discrepancia de audiencia:** El `audience` de la regla debe ser exactamente igual al `aud` del token: el ID de cliente del registro de aplicación de audiencia para los tokens v2.0 que configura esta guía.
* **Discrepancia de nombre de claim:** Una regla que coincide con un claim que el token no lleva nunca pasa. Los tokens v1.0 llevan el ID de cliente en `appid`, no en `azp`; consulta [Si tus tokens son v1.0](https://platform.claude.com/docs/es/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Si tus tokens son v1.0

Esta guía configura el registro de aplicación de audiencia con `api.requestedAccessTokenVersion: 2`, por lo que todos los tokens que muestra son v2.0. Si reutilizas un registro existente que deja `requestedAccessTokenVersion` sin establecer, Entra emite tokens v1.0 en su lugar. Decodifica un token de muestra y revisa su claim `ver`; si es `1.0`, cambian cuatro cosas:

* **Emisor:** El claim `iss` es `https://sts.windows.net/<TENANT_ID>/` en lugar de `https://login.microsoftonline.com/<TENANT_ID>/v2.0`. Registra la URL del emisor exactamente como la lleva el claim `iss` de tu token. Las dos URL comparten el mismo JWKS, por lo que el modo de descubrimiento funciona para cualquiera de las dos.
* **Selector del asistente:** Elige **v1 (sts.windows.net)** en el selector **Token issuer** del asistente Connect workload en lugar de **v2.0 (login.microsoftonline.com)**.
* **Audiencia:** El claim `aud` es el URI de identificador que pasaste como `resource` (por ejemplo, `api://<APP_ID>`), no el ID de cliente del registro. Establece el `audience` de la regla de federación en el valor `aud` exacto de tu token decodificado.
* **Claim de ID de cliente:** El ID de cliente de la identidad que llama aparece en `appid`, no en `azp`. Los dos claims nunca aparecen en el mismo token, por lo que una regla que coincide con `azp` nunca pasa frente a un token v1.0.

Los claims `oid`, `sub` y `tid` llevan los mismos valores en ambas versiones, por lo que el resto de esta guía se aplica sin cambios.

## Delimita tu regla

Una regla de federación puede coincidir con el sujeto del token mediante `subject_prefix` además de (o en lugar de) el mapa `claims`; consulta [Semántica de coincidencia de reglas](https://platform.claude.com/docs/es/manage-claude/wif-reference#rule-matching-semantics) para ver cómo se combinan los campos. Los valores `sub` de Entra para estas identidades son GUID canónicos de longitud fija, por lo que un `subject_prefix` que contenga el ID de objeto completo de 36 caracteres coincide solo con ese sujeto; esta es una propiedad del formato de sujeto de Entra, no de `subject_prefix` en general.

<Warning>
  Todas las identidades de tu inquilino pueden solicitar un token para la audiencia registrada, por lo que `audience` y `tid` por sí solos no identifican una carga de trabajo específica. Una regla que omite una coincidencia de `oid` (o `azp`/`appid`), o que usa un `subject_prefix` con comodín o GUID parcial, autoriza a todas las identidades administradas y entidades de servicio del inquilino.
</Warning>

Restringe el bloque `match` de la regla al alcance más estrecho que se ajuste a tu caso de uso:

* **Haz coincidir `oid` como valor exacto:** Establece `claims.oid` en el ID de objeto completo de la identidad administrada. Un `subject_prefix` establecido en ese ID de objeto completo es equivalente (el asistente de la Console establece ambos); nunca uses un `subject_prefix` con comodín o GUID parcial, que coincide con más identidades de las que pretendes.
* **Fija `tid` como defensa en profundidad:** La URL del emisor ya fija tu inquilino, pero agregar `claims.tid` protege contra la desviación de configuración si el registro del emisor se edita más adelante.
* **Fija la audiencia:** Establece `audience` en el valor `aud` exacto de tu token decodificado para que se rechacen los tokens emitidos para otras aplicaciones.
* **Usa una regla separada para cada identidad administrada:** Crea una regla para cada identidad en lugar de una regla que autorice a varias, de modo que puedas revocar el acceso de una sola carga de trabajo sin afectar a las demás.

## Próximos pasos

* Revisa el modelo de configuración completo en [Workload Identity Federation](https://platform.claude.com/docs/es/manage-claude/workload-identity-federation).
* Consulta las [guías de proveedores](https://platform.claude.com/docs/es/manage-claude/workload-identity-federation#identity-providers) para AWS, Google Cloud, GitHub Actions y Kubernetes.
* Para variables de entorno, archivos de perfil y precedencia de credenciales, consulta la [referencia de WIF](https://platform.claude.com/docs/es/manage-claude/wif-reference).
