---
title: Usar WIF con SPIFFE
url: https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe
description: Autentica cargas de trabajo SPIFFE en la Claude API usando JWT-SVIDs de SPIRE o de cualquier otro emisor compatible con SPIFFE.
---

[SPIFFE](https://spiffe.io/) es el estándar de la CNCF para emitir identidades a cargas de trabajo. [SPIRE](https://spiffe.io/docs/latest/spire-about/) es su implementación de referencia de código abierto, y varios productos comerciales también emiten identidades compatibles con SPIFFE. Anthropic se federa con cualquier implementación de SPIFFE que emita JWT-SVIDs compatibles con OIDC. Para una lista actualizada de implementaciones, consulta [Commercial software that implements SPIFFE](https://spiffe.io/docs/latest/spiffe-about/overview/#commercial-software-that-implements-spiffe) en el sitio del proyecto SPIFFE.

La federación funciona ya sea a través de un documento de descubrimiento OIDC en una URL HTTPS pública (modo `discovery`, sujeto a las [restricciones de URL](https://platform.claude.com/docs/es/manage-claude/wif-reference#url-fields)) o registrando el JWKS directamente (modo `inline`).

La especificación JWT-SVID define `sub` como el SPIFFE ID de la carga de trabajo, y la SPIFFE Workload API requiere que quien llama proporcione `aud` al momento de la obtención, por lo que esos claims son los mismos en todas las implementaciones. Anthropic requiere además `iss` e `iat`, ninguno de los cuales es obligatorio según la especificación JWT-SVID, así que configura tu implementación para que complete ambos (en SPIRE, `iss` es la configuración del servidor `jwt_issuer` e `iat` se establece automáticamente). Con eso en su lugar, las secciones [Configurar Anthropic](https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe#configure-anthropic), [Adquirir y usar el token](https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe#acquire-and-use-the-token) y [Delimitar tu regla](https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe#scope-your-rule) de esta guía aplican a cualquier implementación de SPIFFE.

SPIFFE asigna a cada carga de trabajo un URI de identidad estable con la forma `spiffe://<trust-domain>/<path>`, y SPIRE emite esa identidad como un JWT-SVID bajo demanda a través de la Workload API. Un JWT-SVID es un JWT firmado ordinario cuyo claim `sub` es el SPIFFE ID de la carga de trabajo y cuyo claim `aud` lo proporciona la carga de trabajo al momento de la obtención.

El puente entre un "trust domain" (dominio de confianza) de SPIRE y el OIDC estándar es el [SPIRE OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md), un componente auxiliar independiente que publica `/.well-known/openid-configuration` y un endpoint JWKS para las claves de firma JWT del dominio de confianza. Con el discovery provider en ejecución, un JWT-SVID se valida como cualquier otro token OIDC: registra la URL de descubrimiento como un "federation issuer" (emisor de federación), escribe una "federation rule" (regla de federación) que coincida con el SPIFFE ID de la carga de trabajo, y haz que la carga de trabajo presente su JWT-SVID al endpoint de intercambio de tokens de Anthropic.

Los ejemplos de esta página usan SPIRE y aplican en cualquier lugar donde se ejecute SPIRE Agent: pods de Kubernetes, máquinas virtuales y hosts bare-metal.

<Note>
  Si tu clúster de Kubernetes no ejecuta SPIRE y prefieres autenticarte con los tokens proyectados de cuenta de servicio nativos del clúster, consulta [Usar WIF con Kubernetes](https://platform.claude.com/docs/es/manage-claude/wif-providers/kubernetes).
</Note>

## 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.
* Un despliegue de SPIFFE con identidades de carga de trabajo emitidas (los ejemplos de esta página usan SPIRE Server y Agent), y entradas de registro para las cargas de trabajo que necesitan llamar a la Claude API.
* Un endpoint de descubrimiento OIDC para el dominio de confianza (en SPIRE, el [OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md)) en ejecución con un endpoint HTTPS accesible públicamente, o el JWKS exportado para el registro `inline`.
* Tu emisor SPIFFE configurado para establecer el claim `iss` en los JWT-SVIDs con el valor que registrarás como `issuer_url` del emisor de federación. Para el modo `discovery`, esta es la URL pública del endpoint de descubrimiento (en SPIRE, la configuración del servidor `jwt_issuer`).
* JWT-SVIDs disponibles para tus cargas de trabajo. WIF acepta únicamente JWT-SVIDs, no X.509-SVIDs.
* 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.

El valor de audiencia que debes solicitar al obtener un JWT-SVID es siempre `https://api.anthropic.com`. Usa este valor en el `jwt_audience` de spiffe-helper, en la llamada `FetchJWTSVID` de la Workload API y en el matcher `audience` de la regla de federación.

## Configurar SPIRE

Las instrucciones de esta sección son específicas de SPIRE. Si usas un emisor SPIFFE diferente, configura su endpoint de descubrimiento OIDC y la obtención de JWT-SVID según su propia documentación, y luego continúa en [Configurar Anthropic](https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe#configure-anthropic).

Si ya ejecutas SPIRE con el OIDC Discovery Provider, federarte con Anthropic requiere tres cosas del lado de SPIRE: un `jwt_issuer` que coincida con la URL de descubrimiento, una entrada de registro para la carga de trabajo que llamará a la Claude API, y una forma de que esa carga de trabajo obtenga un JWT-SVID con la audiencia de Anthropic. Las siguientes subsecciones recorren cada una. Los fragmentos de configuración muestran solo los ajustes relevantes para la federación con Anthropic, no configuraciones completas de despliegue de SPIRE.

<Tip>
  ¿Estás configurando SPIRE por primera vez? Despliega SPIRE Server y Agent siguiendo el [inicio rápido de SPIRE](https://spiffe.io/docs/latest/try/), y luego agrega el [OIDC Discovery Provider](https://github.com/spiffe/spire/blob/main/support/oidc-discovery-provider/README.md) como un servicio separado junto a SPIRE Server. La federación en modo discovery depende de que el provider esté desplegado y sea accesible públicamente. El provider no forma parte de una instalación predeterminada de SPIRE.
</Tip>

### Verificar el emisor JWT

Anthropic valida un JWT-SVID comparando su claim `iss` con un emisor de federación registrado y obteniendo el JWKS del documento de descubrimiento de ese emisor. Dos configuraciones de SPIRE deben coincidir en la misma URL: el `jwt_issuer` de SPIRE Server (que se convierte en el claim `iss` de cada JWT-SVID emitido) y la lista `domains` del OIDC Discovery Provider (que determina el host desde el cual se sirven el documento de descubrimiento y el JWKS). Esa URL compartida es la que registras con Anthropic.

El dominio de confianza y la URL del emisor son independientes. El dominio de confianza (`spiffe://prod.example.com`) delimita el claim `sub`. La URL del emisor (`https://oidc-discovery.prod.example.com`) es donde Anthropic obtiene las claves de firma. No necesitan compartir un nombre de host.

Confirma que `jwt_issuer` esté establecido en la configuración de SPIRE Server y apunte a la URL pública del discovery provider. El siguiente ejemplo también muestra una duración predeterminada de JWT-SVID. El valor predeterminado integrado de SPIRE es de 5 minutos, lo cual es lo suficientemente corto como para requerir rotación continua (consulta [Ejecutar spiffe-helper](https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe#run-spiffe-helper)). El endpoint de intercambio de tokens de Anthropic rechaza cualquier token de identidad cuya duración exceda el máximo configurado del emisor de federación, que es de 1 hora por defecto (consulta [Reglas de validación](https://platform.claude.com/docs/es/manage-claude/wif-reference#validation-rules)). Esta verificación aplica a toda implementación de SPIFFE, no solo a SPIRE, así que mantén `default_jwt_svid_ttl` (o cualquier anulación por entrada) en ese máximo o por debajo de él.

```text server.conf
server {
    trust_domain         = "prod.example.com"
    jwt_issuer           = "https://oidc-discovery.prod.example.com"
    default_jwt_svid_ttl = "5m"
    # ...
}
```

En la configuración del OIDC Discovery Provider, el mismo nombre de host debe aparecer bajo `domains`, y el provider debe poder alcanzar el socket de API de SPIRE Server. El provider sirve el documento de descubrimiento y el JWKS sobre HTTPS. Termina TLS con su soporte ACME integrado, o colócalo detrás de un balanceador de carga que lo haga.

```text oidc-discovery-provider.conf
domains = ["oidc-discovery.prod.example.com"]

server_api {
    address = "unix:///run/spire/sockets/private/api.sock"
}

acme {
    email        = "platform@example.com"
    tos_accepted = true
}
```

<Note>
  El ejemplo usa `server_api`, que conecta el discovery provider al socket de API privilegiado de SPIRE Server. El provider también acepta un bloque `workload_api` (con `socket_path` y `trust_domain`) que obtiene el bundle a través de la Workload API de un SPIRE Agent en su lugar. Úsalo cuando el discovery provider no deba tener acceso a la Server API o se ejecute en un nodo que no puede alcanzar el Server.
</Note>

### Registrar la carga de trabajo

Cada carga de trabajo que llama a la Claude API necesita una entrada de registro en SPIRE que mapee sus selectores de tiempo de ejecución a un SPIFFE ID. Si la carga de trabajo ya está registrada, anota su SPIFFE ID, que usarás en el `subject_prefix` de la regla de federación. Si no, regístrala. Para un pod de Kubernetes, los selectores son típicamente el namespace y la cuenta de servicio de Kubernetes:

```bash CLI
# Reemplaza NODE_UID con el UID del nodo:
#   kubectl get node <node-name> -o jsonpath='{.metadata.uid}'
spire-server entry create \
    -spiffeID spiffe://prod.example.com/ns/inference/sa/worker \
    -parentID spiffe://prod.example.com/spire/agent/k8s_psat/prod-cluster/NODE_UID \
    -selector k8s:ns:inference \
    -selector k8s:sa:worker
```

<Note>
  El `parentID` mostrado es el ID de agente autogenerado de un solo nodo. Para un registro a nivel de clúster, asigna como padre de la entrada un [alias de nodo](https://spiffe.io/docs/latest/deploying/registering/#mapping-workloads-to-multiple-nodes) para que coincida con cargas de trabajo en todos los nodos, como lo hace el [inicio rápido de SPIRE en Kubernetes](https://spiffe.io/docs/latest/try/getting-started-k8s/).
</Note>

Las cargas de trabajo fuera de Kubernetes usan selectores a nivel de host como `unix:uid:1000` (`unix:path` también está disponible pero requiere `discover_workload_path = true` en la configuración del workload attestor unix del agente). Los clústeres que ejecutan [spire-controller-manager](https://github.com/spiffe/spire-controller-manager) pueden declarar entradas con el recurso personalizado `ClusterSPIFFEID` en lugar de llamar a `spire-server entry create` directamente.

### Ejecutar spiffe-helper

[spiffe-helper](https://github.com/spiffe/spiffe-helper) es una utilidad sidecar que se conecta al socket de SPIRE Agent, obtiene un JWT-SVID para una audiencia dada, lo escribe en un archivo y lo vuelve a obtener antes de que expire. El helper se ejecuta en modo daemon por defecto. El siguiente ejemplo establece `daemon_mode = true` explícitamente.

```text helper.conf
agent_address = "/run/spire/sockets/agent.sock"
# The JWT-SVID file is written under cert_dir
cert_dir      = "/var/run/secrets/anthropic.com"
daemon_mode   = true

jwt_svids = [{
    jwt_audience       = "https://api.anthropic.com"
    jwt_svid_file_name = "token"
}]
```

En Kubernetes, ejecuta spiffe-helper como un contenedor sidecar que comparte un volumen `emptyDir` respaldado en memoria (`medium: Memory`) con tu contenedor de aplicación, de modo que el SVID portador nunca llegue al disco del nodo. Monta el socket de SPIRE Agent desde el host en el sidecar, monta el volumen compartido en `/var/run/secrets/anthropic.com` en ambos contenedores, y establece `ANTHROPIC_IDENTITY_TOKEN_FILE=/var/run/secrets/anthropic.com/token` en el contenedor de aplicación. En VMs y bare metal, ejecuta spiffe-helper como un servicio del sistema junto a la carga de trabajo y apunta ambos a un directorio compartido.

## Configurar 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 **Custom OIDC**. 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:** Registra la URL pública del OIDC Discovery Provider en modo `discovery`. Anthropic obtiene `/.well-known/openid-configuration` desde esta URL y sigue el `jwks_uri` devuelto para recuperar las claves de firma del dominio de confianza.

```json
{
  "name": "spire-prod",
  "issuer_url": "https://oidc-discovery.prod.example.com",
  "jwks": { "type": "discovery" }
}
```

Si el discovery provider no es accesible desde la internet pública, obtén el JWKS tú mismo (`curl https://oidc-discovery.prod.example.com/keys`) y registra el emisor con `"jwks": {"type": "inline", "keys": [...]}` usando el contenido del arreglo `keys` devuelto. En modo `inline`, el `issuer_url` solo se compara con el claim `iss` del JWT-SVID. Anthropic nunca intenta alcanzarlo.

<Warning>
  SPIRE rota las claves de firma JWT con frecuencia, por defecto con la misma cadencia que la CA (`ca_ttl`, 24 horas). Si registras el emisor con un JWKS inline en lugar de una URL de descubrimiento, debes actualizar el JWKS cada vez que SPIRE rote: agrega la nueva clave antes de que las cargas de trabajo comiencen a presentarla, y **elimina las claves reemplazadas** una vez que los tokens firmados con ellas hayan expirado. Las claves obsoletas que permanezcan en un JWKS inline siguen siendo confiables indefinidamente.
</Warning>

Para automatizar las actualizaciones del JWKS sin exponer un endpoint de descubrimiento público, configura un plugin [BundlePublisher](https://spiffe.io/docs/latest/deploying/spire_server/#built-in-plugins) de SPIRE Server (`aws_s3`, `gcp_cloudstorage` o `k8s_configmap`) con `format = "jwks"` para enviar las claves de firma JWT a un almacenamiento externo en cada rotación, y luego actualiza las claves inline del emisor a través de la [Admin API](https://platform.claude.com/docs/es/manage-claude/wif-admin-api#federation-issuers).

**Regla de federación:** Haz coincidir el `sub` del JWT-SVID (el SPIFFE ID) y el `aud` que configuraste para que spiffe-helper solicite. Los SPIFFE IDs son cadenas URI y `subject_prefix` los compara como texto opaco, por lo que tanto un valor exacto como una coincidencia de prefijo con `*` al final funcionan con ellos. Para patrones más complejos, usa una `condition` CEL.

```json
{
  "name": "spire-inference-worker",
  "issuer_id": "fdis_...",
  "match": {
    "subject_prefix": "spiffe://prod.example.com/ns/inference/sa/worker",
    "audience": "https://api.anthropic.com"
  },
  "target": {
    "type": "service_account",
    "service_account_id": "svac_..."
  },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}
```

`token_lifetime_seconds` es la duración del token de acceso de Anthropic que devuelve el intercambio, no la del JWT-SVID. El SDK renueva el token de acceso automáticamente.

Sé tan específico como la carga de trabajo lo permita. Relaja `subject_prefix` a `spiffe://prod.example.com/ns/inference/*` solo si todas las cargas de trabajo registradas bajo esa ruta deben mapearse a la misma cuenta de servicio de Anthropic. Agrega el ID `fdrl_...` de la regla a la variable de entorno `ANTHROPIC_FEDERATION_RULE_ID` de la carga de trabajo.

## Adquirir y usar el token

El SDK de Claude puede leer el JWT-SVID del archivo que mantiene spiffe-helper o, excepto en Java, llamar directamente a la SPIFFE Workload API mediante un proveedor de tokens. La ruta basada en archivos es la integración más sencilla y funciona en todos los lenguajes del SDK. La ruta con proveedor de tokens elimina el sidecar, pero requiere un cliente de la SPIFFE Workload API en el lenguaje de tu aplicación.

<Tabs>
  <Tab title="Basado en archivo con spiffe-helper">
    Con spiffe-helper escribiendo un JWT-SVID nuevo en `/var/run/secrets/anthropic.com/token`, establece `ANTHROPIC_IDENTITY_TOKEN_FILE` en esa ruta junto con `ANTHROPIC_FEDERATION_RULE_ID`, `ANTHROPIC_ORGANIZATION_ID`, `ANTHROPIC_SERVICE_ACCOUNT_ID` y `ANTHROPIC_WORKSPACE_ID`. El SDK lee el archivo en cada intercambio de tokens, por lo que siempre toma el SVID rotado más recientemente, y renueva el token de acceso de Anthropic automáticamente antes de que expire. Consulta [Variables de entorno](https://platform.claude.com/docs/es/manage-claude/wif-reference#environment-variables) para saber de dónde proviene cada valor.

    <CodeGroup>
      ```bash cURL
      JWT=$(cat "$ANTHROPIC_IDENTITY_TOKEN_FILE")

      ACCESS_TOKEN=$(curl -sS https://api.anthropic.com/v1/oauth/token \
        -H "content-type: application/json" \
        --data @- <<JSON | jq -r .access_token
      {
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "assertion": "$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
      )

      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, Claude"}]
        }' | jq -r '.content[] | select(.type == "text") | .text'
      ```

      ```bash CLI
      # Lee el JWT-SVID que spiffe-helper escribe en
      # ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      ant messages create \
        --model claude-opus-5-5 \
        --max-tokens 1024 \
        --message '{role: user, content: "Hello, Claude"}'
      ```

      ```python Python
      import anthropic

      # Lee el JWT-SVID que spiffe-helper escribe en
      # ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      client = anthropic.Anthropic()

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

      ```typescript TypeScript
      import Anthropic from "@anthropic-ai/sdk";

      // Lee el JWT-SVID que spiffe-helper escribe en
      // ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      const client = new Anthropic();

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

      ```csharp C#
      // Lee el JWT-SVID que spiffe-helper escribe en
      // ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      using var client = new AnthropicClient();

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

      ```go Go
      // Lee el JWT-SVID que spiffe-helper escribe en
      // ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      client := anthropic.NewClient()

      message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
      	Model:     anthropic.ModelClaudeOpus5_5,
      	MaxTokens: 1024,
      	Messages: []anthropic.MessageParam{
      		anthropic.NewUserMessage(anthropic.NewTextBlock("Hello, Claude")),
      	},
      })
      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
      // Lee el JWT-SVID que spiffe-helper escribe en
      // ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

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

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

      ```php PHP
      use Anthropic\Client;

      // Lee el JWT-SVID que spiffe-helper escribe en
      // ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      // ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      $client = new Client();

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

      ```ruby Ruby
      require "anthropic"

      # Lee el JWT-SVID que spiffe-helper escribe en
      # ANTHROPIC_IDENTITY_TOKEN_FILE, además de ANTHROPIC_FEDERATION_RULE_ID,
      # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID y ANTHROPIC_WORKSPACE_ID.
      client = Anthropic::Client.new

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

  <Tab title="Proveedor de tokens a través de la SPIFFE Workload API">
    Excepto en Java, las cargas de trabajo que enlazan directamente un cliente de la SPIFFE Workload API pueden omitir spiffe-helper y pasar al SDK un proveedor de tokens que obtenga un JWT-SVID nuevo desde el socket del agente. El SDK invoca el proveedor antes de cada intercambio de tokens, por lo que la carga de trabajo siempre presenta un SVID no expirado. Python ([py-spiffe](https://github.com/HewlettPackard/py-spiffe)) y Go ([go-spiffe](https://github.com/spiffe/go-spiffe)) tienen clientes maduros de la Workload API.

    <CodeGroup exclude="shell, typescript, java, csharp, php, ruby">
      ```python Python
      import os
      import anthropic
      from anthropic import WorkloadIdentityCredentials
      from spiffe import JwtSource

      AUDIENCE = "https://api.anthropic.com"

      # Se conecta al socket del SPIRE Agent en SPIFFE_ENDPOINT_SOCKET.
      jwt_source = JwtSource()


      def fetch_jwt_svid() -> str:
          svid = jwt_source.fetch_svid(audience={AUDIENCE})  # audience is a set of strings
          return svid.token


      client = anthropic.Anthropic(
          credentials=WorkloadIdentityCredentials(
              identity_token_provider=fetch_jwt_svid,
              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, Claude"}],
      )
      print(next(block.text for block in message.content if block.type == "text"))
      ```

      ```go Go
      import (
      	"context"
      	"fmt"
      	"os"

      	"github.com/anthropics/anthropic-sdk-go"
      	"github.com/anthropics/anthropic-sdk-go/option"
      	"github.com/spiffe/go-spiffe/v2/svid/jwtsvid"
      	"github.com/spiffe/go-spiffe/v2/workloadapi"
      )
      // ...
      	const audience = "https://api.anthropic.com"

      	ctx := context.Background()
      	source, err := workloadapi.NewJWTSource(ctx)
      	if err != nil {
      		panic(err)
      	}
      	defer source.Close()

      	fetchJWTSVID := func(ctx context.Context) (string, error) {
      		svid, err := source.FetchJWTSVID(ctx, jwtsvid.Params{Audience: audience})
      		if err != nil {
      			return "", err
      		}
      		return svid.Marshal(), nil
      	}

      	client := anthropic.NewClient(
      		option.WithFederationTokenProvider(fetchJWTSVID, 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(ctx, anthropic.MessageNewParams{
      		Model:     anthropic.ModelClaudeOpus5_5,
      		MaxTokens: 1024,
      		Messages: []anthropic.MessageParam{
      			anthropic.NewUserMessage(anthropic.NewTextBlock("Hello, Claude")),
      		},
      	})
      	if err != nil {
      		panic(err)
      	}
      	for _, block := range message.Content {
      		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
      			fmt.Println(textBlock.Text)
      			break
      		}
      	}
      ```
    </CodeGroup>

    <Note>
      Para otros lenguajes, obtén el JWT-SVID con el cliente de la SPIFFE Workload API de tu entorno de ejecución (o ejecuta `spire-agent api fetch jwt` desde la shell), escríbelo en un archivo y establece `ANTHROPIC_IDENTITY_TOKEN_FILE` en esa ruta como en la pestaña basada en archivo.
    </Note>
  </Tab>
</Tabs>

## Verificar la configuración

Antes de integrar el SDK, obtén un JWT-SVID directamente desde SPIRE Agent y confirma que los claims coincidan con lo que espera tu regla de federación. Si usas una implementación de SPIFFE diferente, obtén un JWT-SVID con su CLI o cliente de la Workload API y decodifica el payload de la misma manera.

<Note>
  La Workload API atestigua el proceso que llama. Para una entrada de registro de Kubernetes, ejecuta este comando dentro de un pod que satisfaga los selectores de la entrada y tenga el socket del agente montado (por ejemplo, usando `kubectl exec`). En VMs y bare metal, ejecútalo como el usuario o proceso que coincida con los selectores `unix:` de la entrada. Ejecutarlo desde una shell de host no atestiguada devuelve `no identity issued`, que es la falla más común en el paso de verificación.
</Note>

```bash CLI
spire-agent api fetch jwt \
    -audience https://api.anthropic.com \
    -socketPath /run/spire/sockets/agent.sock \
    -output json \
  | jq -r '.[0].svids[0].svid' \
  | jq -rR 'split(".")[1] | gsub("-";"+") | gsub("_";"/") | @base64d | fromjson'
```

La opción `-output json` devuelve la respuesta del SVID y la respuesta del bundle como un arreglo JSON de dos elementos, por lo que `jq -r '.[0].svids[0].svid'` extrae el token sin más. En versiones anteriores de SPIRE sin `-output`, el comando imprime en su lugar un bloque etiquetado. En ese caso, canaliza la salida predeterminada a través de `awk '/^[[:space:]]*eyJ/{print $1; exit}'` para extraer la línea del token. Comprueba que `iss` sea la URL del OIDC Discovery Provider que registraste, que `sub` sea el SPIFFE ID de la carga de trabajo y que `aud` contenga `https://api.anthropic.com`. Luego ejecuta el ejemplo de cURL de [Adquirir y usar el token](https://platform.claude.com/docs/es/manage-claude/wif-providers/spiffe#acquire-and-use-the-token). Un intercambio exitoso devuelve un `access_token` que comienza con `sk-ant-oat01-`. 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 del rechazo y consulta [Solucionar un intercambio fallido](https://platform.claude.com/docs/es/manage-claude/wif-reference#troubleshoot-a-failed-exchange). La causa más común del lado de SPIRE es una discrepancia entre el `jwt_issuer` de SPIRE Server y la URL registrada como emisor de federación.

## Delimitar tu regla

Las convenciones de ruta de los SPIFFE IDs las define el operador, por lo que el matcher `subject_prefix` de la regla de federación debe reflejar el esquema de rutas que usan tus entradas de registro. Los esquemas comunes incluyen `spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>` (el predeterminado emitido por el recurso `ClusterSPIFFEID` en spire-controller-manager) y `spiffe://<trust-domain>/host/<hostname>/<service>` para cargas de trabajo en VMs y bare-metal.

<Warning>
  Un `subject_prefix` de `spiffe://prod.example.com/*` coincide con todas las cargas de trabajo del dominio de confianza. Sin un matcher `audience`, la regla también acepta JWT-SVIDs emitidos para cualquier audiencia, incluidos los que la carga de trabajo solicitó para relying parties no relacionadas.
</Warning>

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

* **Fijar a una sola carga de trabajo:** Establece `subject_prefix` con el SPIFFE ID completo sin `*` al final.
* **Establecer siempre una audiencia:** Exige `audience` en la regla y configura spiffe-helper (o la llamada a la Workload API) con el mismo valor para que los SVIDs emitidos para otras relying parties sean rechazados.
* **Delimitar por segmento de ruta:** Usa `spiffe://prod.example.com/ns/inference/*` para otorgar acceso a todas las cargas de trabajo registradas bajo un namespace, y crea una regla y una cuenta de servicio de Anthropic separadas por namespace en lugar de ampliar una sola regla.
* **Un emisor por dominio de confianza:** Cada dominio de confianza de SPIRE tiene sus propias claves de firma y su propio OIDC Discovery Provider. Registra cada uno como un emisor de federación separado y vincula las reglas al emisor que posee los SPIFFE IDs con los que coinciden.

## Próximos pasos

<CardGroup cols={2}>
  <Card title="Usar WIF con Okta" icon="lock" href="https://platform.claude.com/docs/es/manage-claude/wif-providers/okta">
    Federa identidades de aplicaciones de servicio de Okta con la Claude API mediante Workload Identity Federation.
  </Card>

  <Card title="Workload Identity Federation" icon="cloud" href="https://platform.claude.com/docs/es/manage-claude/workload-identity-federation">
    Autentica cargas de trabajo en la Claude API con tokens de identidad de corta duración de tu propio proveedor de identidad en lugar de claves de API estáticas de larga duración.
  </Card>

  <Card title="Referencia de WIF" icon="book" href="https://platform.claude.com/docs/es/manage-claude/wif-reference">
    Variables de entorno, reglas de validación, configuración de perfiles y referencia de errores para Workload Identity Federation.
  </Card>

  <Card title="Usar WIF con Kubernetes" icon="cube" href="https://platform.claude.com/docs/es/manage-claude/wif-providers/kubernetes">
    Autentícate en la Claude API desde clústeres de Kubernetes autogestionados usando tokens proyectados de cuenta de servicio.
  </Card>
</CardGroup>
