---
title: Utiliser WIF avec Microsoft Entra ID
url: https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure
description: Fédérez les identités managées Azure et Entra Workload Identity avec la Claude API afin que vos charges de travail Azure puissent appeler Claude sans clés API statiques.
---

Les charges de travail Azure s'authentifient auprès de la Claude API en présentant un « JSON Web Token » (jeton web JSON), ou JWT, émis par Microsoft Entra ID, puis en l'échangeant contre un jeton d'accès Anthropic de courte durée. La configuration suit le même schéma sur chaque plateforme Azure :

1. **Enregistrer l'audience du jeton :** créez une « app registration » (inscription d'application) dans votre « tenant » (locataire) Microsoft Entra pour représenter l'audience de la Claude API. Chaque charge de travail du locataire demande des jetons Entra pour celle-ci.
2. **Configurer l'identité pour votre plateforme :** une « managed identity » (identité managée) sur les machines virtuelles, les VM Scale Sets, App Service, Functions et Container Apps, ou Entra Workload Identity sur AKS.
3. **Configurer Anthropic :** enregistrez l'émetteur Entra de votre locataire, créez un compte de service et rédigez une règle de fédération qui correspond aux « claims » (revendications) du jeton.
4. **Échanger à l'exécution :** votre charge de travail échange son jeton émis par Entra via `POST /v1/oauth/token` contre un jeton d'accès Anthropic `sk-ant-oat01-...` et appelle Claude avec celui-ci.

Dans les deux parcours, le jeton que vous présentez à Anthropic contient l'émetteur Entra propre à votre locataire et l'ID d'objet de l'identité managée dans les revendications `sub` et `oid` ; seule la manière dont la charge de travail obtient ce jeton diffère. Choisissez la section correspondant à l'endroit où s'exécute votre charge de travail : [Utiliser une identité managée](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#use-a-managed-identity) pour les machines virtuelles, les VM Scale Sets, App Service, Functions ou Container Apps ; [Utiliser Entra Workload Identity sur AKS](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#use-entra-workload-identity-on-aks) pour AKS.

## Prérequis

* Une familiarité avec les [concepts WIF](https://platform.claude.com/docs/fr/manage-claude/workload-identity-federation#concepts) : comptes de service, émetteurs de fédération et règles de fédération.
* Un abonnement Azure avec l'autorisation d'attribuer des identités managées (ou de configurer Entra Workload Identity sur AKS).
* L'autorisation de créer une inscription d'application et un « service principal » (principal de service) dans votre locataire Microsoft Entra (l'audience partagée de la Claude API). Entra n'émet des jetons que pour une audience qui existe dans le locataire ; l'étape [Enregistrer l'audience du jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#register-the-token-audience) est donc requise avant qu'une demande de jeton puisse aboutir.
* L'ID de votre locataire Microsoft Entra. Vous le trouverez dans le portail Azure sous **Microsoft Entra ID → Overview → Tenant ID**.
* L'autorisation de créer des comptes de service, des émetteurs de fédération et des règles de fédération dans la Claude Console pour votre organisation Anthropic.

## Enregistrer l'audience du jeton

Microsoft Entra ID n'émet un jeton que lorsque l'audience demandée existe dans votre locataire sous la forme d'une inscription d'application dotée d'un principal de service. Créez une inscription d'application pour représenter l'audience de la Claude API ; chaque charge de travail du locataire peut demander des jetons pour celle-ci. Sans cette inscription, les demandes de jeton échouent avec une erreur « resource not found in tenant » (`AADSTS50001` depuis les points de terminaison d'identité managée, `AADSTS500011` depuis le point de terminaison de jeton Entra).

```bash
# Créez l'inscription d'application qui représente l'audience de la Claude API.
APP_ID=$(az ad app create --display-name claude-api-federation --query appId -o tsv)

# Demandez des jetons d'accès v2.0 et définissez l'URI d'identifiant api://<APP_ID>.
az ad app update --id "$APP_ID" \
  --identifier-uris "api://$APP_ID" \
  --set api.requestedAccessTokenVersion=2

# Créez le principal de service afin que l'audience soit résolue dans votre locataire.
az ad sp create --id "$APP_ID"
```

<Note>
  Utilisez le format d'URI d'identifiant `api://<APP_ID>`. Entra restreint les URI d'identifiant `https://` aux domaines vérifiés de votre propre locataire ; une URI telle que `https://api.anthropic.com` ne peut donc pas être enregistrée dans la plupart des locataires, tandis que `api://<APP_ID>` est acceptée partout. Avec `requestedAccessTokenVersion: 2`, les jetons pour cette audience sont en v2.0, ce que ce guide suppose. Si vous réutilisez une inscription existante qui émet des jetons v1.0, consultez [Si vos jetons sont en v1.0](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
</Note>

## Utiliser une identité managée

Utilisez ce parcours lorsque votre charge de travail s'exécute sur une machine virtuelle, un VM Scale Set, App Service, Functions ou Container Apps. La charge de travail demande un JWT émis par Entra pour l'identité managée qui lui est attribuée auprès du point de terminaison de jeton local de la plateforme, puis échange ce JWT avec Anthropic.

### Configurer l'identité managée

<Steps>
  <Step title="Attacher une identité managée">
    Activez une identité managée affectée par le système ou affectée par l'utilisateur sur votre ressource Azure. Dans le portail Azure, ouvrez la ressource, accédez à **Identity** et activez **System assigned** (ou attachez une identité affectée par l'utilisateur).

    Une fois l'identité créée, notez son **Object (principal) ID**. Ce GUID apparaît à la fois dans les revendications `sub` et `oid` du jeton émis, et votre règle de fédération Anthropic effectuera la correspondance sur celui-ci. Vous le trouverez sur la page **Identity** de la ressource ; pour une identité affectée par l'utilisateur, il s'agit de l'**Object (principal) ID** sur la page **Overview** de la ressource d'identité managée. (Une identité managée ne possède qu'un principal de service dans Microsoft Entra ID, pas d'inscription d'application.)
  </Step>

  <Step title="Trouver le point de terminaison de jeton de la plateforme">
    La plateforme expose un point de terminaison de jeton local une fois l'identité attachée :

    * **Machines virtuelles et VM Scale Sets :** IMDS à l'adresse `http://169.254.169.254/metadata/identity/oauth2/token` avec l'en-tête `Metadata: true` et `api-version=2018-02-01`.
    * **App Service, Functions et Container Apps :** l'URL contenue dans la variable d'environnement `IDENTITY_ENDPOINT` avec l'en-tête `X-IDENTITY-HEADER` défini sur la valeur de `IDENTITY_HEADER`, et `api-version=2019-08-01`. IMDS n'est pas accessible sur ces plateformes.

    Si la ressource possède plus d'une identité managée affectée par l'utilisateur, ajoutez `client_id=<IDENTITY_CLIENT_ID>` à la demande de jeton pour en sélectionner une. Azure recommande de toujours le spécifier. Sans cela, le résultat dépend de la présence ou non d'une identité affectée par le système également activée sur la ressource : si c'est le cas, la demande bascule silencieusement sur cette identité puis échoue à la correspondance `oid` de votre règle de fédération ; si ce n'est pas le cas, la demande échoue purement et simplement dès qu'une deuxième identité affectée par l'utilisateur est attachée.
  </Step>

  <Step title="Décoder un exemple de jeton">
    Demandez un jeton au point de terminaison et décodez sa charge utile pour confirmer les revendications sur lesquelles votre règle de fédération doit effectuer la correspondance. (Pour la commande de décodage, consultez [Dépanner un échange en échec](https://platform.claude.com/docs/fr/manage-claude/wif-reference#troubleshoot-a-failed-exchange).) Un jeton v2.0 pour une identité managée contient ces revendications :

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

    | Revendication | Valeur                                                                                                                                                                                                             | Effectuez la correspondance sur celle-ci lorsque                                                                                                                                                                                                                    |
    | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `oid`         | L'ID d'objet de l'identité managée, identique à `sub`                                                                                                                                                              | Vous souhaitez autoriser une identité managée spécifique. C'est le comportement par défaut ; la règle de [Configurer Anthropic](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#configure-anthropic) effectue la correspondance sur celle-ci. |
    | `azp`         | L'ID client de l'identité appelante                                                                                                                                                                                | Vous souhaitez autoriser toutes les charges de travail qui partagent une même inscription d'application. Pour une identité managée, `azp` est propre à cette identité, il est donc équivalent à `oid`.                                                              |
    | `aud`         | L'ID client de l'inscription d'application d'audience (le GUID `<APP_ID>` de [Enregistrer l'audience du jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#register-the-token-audience)) | Toujours. Le champ `audience` de la règle doit être exactement égal à la valeur `aud` du jeton.                                                                                                                                                                     |
    | `tid`         | L'ID de votre locataire                                                                                                                                                                                            | Vous souhaitez une défense en profondeur. L'URL de l'émetteur fixe déjà le locataire.                                                                                                                                                                               |

    Si la revendication `ver` du jeton décodé vaut `1.0`, les noms et valeurs des revendications diffèrent. Consultez [Si vos jetons sont en v1.0](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0) avant de continuer.
  </Step>
</Steps>

### Configurer Anthropic

Dans la Claude Console, accédez à la page [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), cliquez sur **Connect workload** et sélectionnez la tuile **Microsoft Entra**. L'assistant vous guide dans l'enregistrement de l'émetteur, la création d'un compte de service et la création d'une règle de fédération.

L'assistant crée ces ressources pour vous. Utilisez les valeurs suivantes, que vous les saisissiez dans l'assistant ou que vous les envoyiez à l'[Admin API](https://platform.claude.com/docs/fr/manage-claude/wif-admin-api) :

**Émetteur de fédération :** choisissez **v2.0 (login.microsoftonline.com)** dans le sélecteur **Token issuer** de l'assistant. (Le sélecteur est défini par défaut sur v1 ; cette valeur par défaut existe pour les locataires qui réutilisent d'anciennes inscriptions émettant encore des jetons v1.0.) Entra publie un document de découverte OIDC à l'URL d'émetteur propre au locataire ; utilisez donc le mode découverte. Chaque locataire Microsoft Entra que vous fédérez nécessite son propre enregistrement d'émetteur.

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

<Warning>
  Les charges de travail à identité managée nécessitent `max_jwt_lifetime_seconds: 86400`. Azure émet des jetons d'identité managée avec jusqu'à 24 heures entre `iat` et `exp`, car il met en cache le jeton de chaque ressource pendant cette période et n'offre aucun moyen de forcer un renouvellement anticipé ; la valeur par défaut d'une heure de l'émetteur rejette ces jetons, et l'échange échoue donc avec la réponse opaque `401` `authentication_error` (message `Authentication failed`). La tuile Microsoft Entra de l'assistant Connect workload crée l'émetteur avec `max_jwt_lifetime_seconds` défini sur `7500` et ne fournit aucun champ pour le modifier lors de la création ; terminez donc l'assistant, puis ouvrez l'onglet **Issuers** de la page [Workload identity](https://platform.claude.com/settings/workload-identity-federation) dans la Claude Console, modifiez l'émetteur et augmentez la valeur à `86400`. Vous pouvez également mettre à jour l'émetteur via l'Admin API.
</Warning>

Une durée de vie acceptée plus longue signifie qu'un jeton Entra divulgué reste échangeable plus longtemps. Si un jeton est divulgué, le levier consiste à désactiver la règle de fédération ; une correspondance stricte sur `oid` limite en premier lieu les identités pouvant échanger un jeton, comme décrit dans [Délimiter votre règle](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#scope-your-rule).

**Règle de fédération :** effectuez la correspondance sur l'ID d'objet de l'identité managée et l'ID de votre locataire. Pour les jetons v2.0 que ce guide configure, la valeur `audience` est l'ID client de l'inscription d'application d'audience (le GUID `<APP_ID>` de [Enregistrer l'audience du jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#register-the-token-audience)). Utilisez la valeur `aud` exacte de votre jeton décodé.

```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` est la durée de vie du jeton d'accès Anthropic renvoyé par l'échange, et non celle du jeton Entra ; le SDK le renouvelle pour vous.

### Acquérir et utiliser le jeton

À l'exécution, votre charge de travail récupère son jeton Entra, l'échange sur `POST /v1/oauth/token` et utilise le jeton bearer renvoyé pour appeler Claude. Le SDK Claude gère l'échange et la boucle de renouvellement lorsque vous fournissez `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), comme le montrent les exemples suivants. Sauf en Java (voir le commentaire dans cet exemple), cette option accepte un fournisseur de jetons, et le SDK l'appelle à nouveau à chaque renouvellement. L'onglet cURL présente le flux brut.

Les exemples récupèrent le jeton d'identité managée auprès du point de terminaison de jeton de la plateforme : IMDS sur les machines virtuelles et les VM Scale Sets, ou le service `IDENTITY_ENDPOINT` sur App Service, Functions et Container Apps. Remplacez `<APP_ID>` dans la valeur de ressource `api://<APP_ID>` par l'ID client de l'inscription d'application d'audience de [Enregistrer l'audience du jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#register-the-token-audience).

<Tip>
  Si votre charge de travail utilise déjà la bibliothèque cliente Azure Identity, obtenez le jeton Entra à partir de celle-ci (`DefaultAzureCredential` avec la portée `api://<APP_ID>/.default`) au lieu d'appeler directement les points de terminaison de jeton. Fournissez-le à `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) comme le font les exemples. La bibliothèque sélectionne le bon point de terminaison sur chaque plateforme Azure, y compris AKS avec Entra Workload Identity.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Récupérez le jeton émis par Entra (identité managée).
  #    Sur une VM ou un VM Scale Set, utilisez IMDS. Avec plusieurs identités
  #    attribuées par l'utilisateur, ajoutez &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)

  #    Sur App Service, Functions ou Container Apps, utilisez plutôt le service
  #    de jetons local (IMDS n'y est pas accessible) :
  # 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)

  #    Pour AKS avec Entra Workload Identity, utilisez plutôt l'échange en deux étapes
  #    décrit dans la section « Use Entra Workload Identity on AKS ».

  # 2. Échangez-le contre un jeton d'accès 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. Appelez l'API Claude avec le jeton 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

  # L'URI d'identificateur de l'inscription d'application d'audience (voir Inscrire l'audience du jeton).
  AUDIENCE = "api://<APP_ID>"


  def fetch_entra_token() -> str:
      """Fetch a managed identity token from the platform's token endpoint."""
      # Avec plusieurs identités affectées par l'utilisateur, ajoutez client_id=<IDENTITY_CLIENT_ID>
      # aux paramètres de la requête pour en sélectionner une.
      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 ou 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";

  // L'URI d'identificateur de l'inscription d'application de l'audience (voir Inscrire l'audience du jeton).
  const AUDIENCE = "api://<APP_ID>";

  async function fetchEntraToken(): Promise<string> {
    // App Service, Functions et Container Apps injectent IDENTITY_ENDPOINT ;
    // Les VM et les VM Scale Sets utilisent IMDS.
    // Avec plusieurs identités attribuées par l'utilisateur, ajoutez &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"
  )

  // L'URI d'identificateur de l'inscription d'application d'audience (voir Inscrire l'audience du jeton).
  const audience = "api://<APP_ID>"

  // fetchEntraToken récupère un jeton d'identité managée depuis le point de terminaison
  // de jetons de la plateforme : IMDS sur les VM et VM Scale Sets, ou le service IDENTITY_ENDPOINT
  // sur App Service, Functions et Container Apps.
  func fetchEntraToken(ctx context.Context) (string, error) {
  	// Avec plusieurs identités affectées par l'utilisateur, ajoutez &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();
      // L'URI d'identificateur de l'inscription d'application de l'audience (voir Inscrire l'audience du jeton).
      String audience = "api://<APP_ID>";
      // App Service, Functions et Container Apps injectent IDENTITY_ENDPOINT ;
      // Les VM et les VM Scale Sets utilisent IMDS.
      // Avec plusieurs identités attribuées par l'utilisateur, ajoutez &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();

      // Le SDK Java accepte le jeton lui-même ou un chemin de fichier, pas une fonction ; avec
      // source("value"), path(...) contient le jeton. Le SDK envoie ce même jeton
      // à chaque actualisation du jeton d'accès Anthropic, ce qui échoue dès qu'il a
      // expiré ou, s'il possède une revendication jti, été utilisé. Pour un processus
      // de longue durée, passez source("file") et écrivez un nouveau jeton dans le fichier avant
      // chaque actualisation.
      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
  {
      // L'URI d'identificateur de l'inscription d'application de l'audience (voir Register the token audience).
      private const string Audience = "api://<APP_ID>";

      private static readonly HttpClient httpClient = new();

      public async Task<string> GetIdentityTokenAsync(CancellationToken ct = default)
      {
          // App Service, Functions et Container Apps injectent IDENTITY_ENDPOINT ;
          // Les VM et VM Scale Sets utilisent IMDS.
          // Avec plusieurs identités attribuées par l'utilisateur, ajoutez &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;

  // L'URI d'identifiant de l'inscription d'application d'audience (voir Inscrire l'audience du jeton).
  const AUDIENCE = 'api://<APP_ID>';

  class EntraIdentityToken implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          // App Service, Functions et Container Apps injectent IDENTITY_ENDPOINT ;
          // Les VM et VM Scale Sets utilisent IMDS.
          // Avec plusieurs identités attribuées par l'utilisateur, ajoutez &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"

  # L'URI d'identifiant de l'inscription d'application de l'audience (voir Inscrire l'audience du jeton).
  AUDIENCE = "api://<APP_ID>"

  def fetch_entra_token
    # App Service, Functions et Container Apps injectent IDENTITY_ENDPOINT ;
    # Les VM et VM Scale Sets utilisent IMDS.
    # Avec plusieurs identités attribuées par l'utilisateur, ajoutez &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
  # Écrivez le jeton d'accès émis par Entra dans un fichier lisible par la CLI.
  # Exemple pour une VM ou un VM Scale Set (IMDS). Sur App Service, Functions ou
  # Container Apps, récupérez-le plutôt depuis "$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=api://<APP_ID>"
  # avec -H "X-IDENTITY-HEADER: $IDENTITY_HEADER".
  # Avec plusieurs identités attribuées par l'utilisateur, ajoutez &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 et ANTHROPIC_WORKSPACE_ID sont lus depuis l'environnement.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### Vérifier la configuration

Depuis votre ressource Azure, exécutez l'échange cURL présenté dans [Acquérir et utiliser le jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#acquire-and-use-the-token) et vérifiez que `POST /v1/oauth/token` renvoie un `200` avec un `access_token` commençant par `sk-ant-oat01-` et une valeur `expires_in` en secondes. Si l'échange échoue avec la réponse opaque `401` `authentication_error` (message `Authentication failed`), consultez la [page d'historique d'authentification](https://platform.claude.com/settings/workload-identity-federation?tab=history) dans la Claude Console pour connaître le motif du refus, puis décodez le jeton Entra (consultez [Dépanner un échange échoué](https://platform.claude.com/docs/fr/manage-claude/wif-reference#troubleshoot-a-failed-exchange) pour la commande) et vérifiez les causes les plus courantes côté Azure :

* **Non-concordance de l'émetteur :** l'`issuer_url` enregistrée doit correspondre exactement à la revendication `iss` du jeton. Un jeton v2.0 contient `https://login.microsoftonline.com/<TENANT_ID>/v2.0` ; si la revendication `ver` décodée vaut `1.0`, consultez [Si vos jetons sont en v1.0](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Durée de vie du jeton :** les jetons d'identité managée comportent jusqu'à 24 heures entre `iat` et `exp`. Si l'émetteur a toujours la valeur `7500` de l'assistant (ou la valeur par défaut d'une heure), augmentez `max_jwt_lifetime_seconds` à `86400` comme décrit dans [Configurer Anthropic](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#configure-anthropic).
* **Non-concordance de l'audience :** l'`audience` de la règle doit être exactement égale à l'`aud` du jeton : l'ID client de l'inscription d'application d'audience pour les jetons v2.0 que ce guide configure.
* **Non-concordance du nom de revendication :** une règle qui effectue la correspondance sur une revendication absente du jeton ne passe jamais. Les jetons v1.0 contiennent l'ID client dans `appid`, et non dans `azp` ; consultez [Si vos jetons sont en v1.0](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Utiliser Entra Workload Identity sur AKS

Utilisez ce parcours lorsque votre charge de travail s'exécute dans un pod AKS. Entra Workload Identity fédère un compte de service Kubernetes avec une identité managée affectée par l'utilisateur : Kubernetes projette un jeton de compte de service (signé par l'émetteur OIDC du cluster AKS) dans le pod au chemin indiqué dans `AZURE_FEDERATED_TOKEN_FILE`. Ce jeton projeté n'est pas un jeton émis par Entra ; pour rester sur le parcours passant par Entra décrit sur cette page, la charge de travail effectue donc un échange en deux étapes : elle échange d'abord le jeton projeté auprès de `https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token` (octroi `client_credentials` fédéré) contre un jeton d'accès émis par Entra, puis transmet ce jeton Entra au SDK Anthropic comme jeton d'identité.

<Tip>
  Les pods AKS peuvent également ignorer l'échange Entra et présenter directement à Anthropic le jeton de compte de service projeté par Kubernetes. Ce parcours enregistre l'émetteur OIDC de votre cluster AKS auprès d'Anthropic au lieu de votre locataire Entra. Consultez [Utiliser WIF avec Kubernetes](https://platform.claude.com/docs/fr/manage-claude/wif-providers/kubernetes) pour ce flux.
</Tip>

### Configurer Entra Workload Identity

<Steps>
  <Step title="Activer l'émetteur OIDC et l'identité de charge de travail sur votre cluster">
    L'activation de l'identité de charge de travail installe pour vous le webhook de mutation `azure-workload-identity` ; ne le déployez manuellement que sur les clusters non AKS. Récupérez l'URL de l'émetteur OIDC du cluster pour les informations d'identification fédérées que vous créerez à une étape ultérieure.

    ```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="Créer une identité managée affectée par l'utilisateur">
    Récupérez deux valeurs de l'identité : le **Client ID** va dans l'annotation du compte de service (et est injecté dans le pod sous la forme `AZURE_CLIENT_ID`), et l'**Object (principal) ID** apparaît dans la revendication `oid` sur laquelle votre règle de fédération Anthropic effectue la correspondance.

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

    # À placer dans l'annotation du compte de service ; injecté dans le pod sous le nom AZURE_CLIENT_ID.
    IDENTITY_CLIENT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query clientId -o tsv)

    # Apparaît comme la revendication oid à laquelle votre règle de fédération correspond.
    IDENTITY_OBJECT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query principalId -o tsv)
    ```
  </Step>

  <Step title="Créer le compte de service Kubernetes annoté">
    Le webhook `azure-workload-identity` lit l'annotation `azure.workload.identity/client-id` pour injecter `AZURE_CLIENT_ID` dans le pod, que les exemples de [Acquérir et utiliser le jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) lisent depuis l'environnement.

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

  <Step title="Créer les informations d'identification fédérées sur l'identité managée">
    Les informations d'identification fédérées font confiance à l'émetteur OIDC de votre cluster pour ce compte de service spécifique. La valeur `--audience api://AzureADTokenExchange` est l'audience fixe d'Entra pour les jetons de compte de service Kubernetes entrants ; elle n'a aucun lien avec l'audience de la Claude API que vous avez enregistrée précédemment.

    ```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="Étiqueter le pod et définir son compte de service">
    Le pod doit porter l'étiquette `azure.workload.identity/use: "true"` et s'exécuter en tant que compte de service annoté. Le webhook injecte alors `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` et `AZURE_TENANT_ID` dans le pod. Le fichier situé à `AZURE_FEDERATED_TOKEN_FILE` contient le jeton de compte de service projeté par Kubernetes, signé par l'émetteur OIDC du cluster 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="Décoder un exemple de jeton">
    Le jeton que voit votre règle de fédération Anthropic n'est pas le fichier projeté ; il s'agit du jeton émis par Entra renvoyé par l'échange `client_credentials`. Depuis l'intérieur d'un pod étiqueté, exécutez l'étape 1 de l'exemple cURL de [Acquérir et utiliser le jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) et décodez le résultat. Il présente la même structure de revendications que le parcours par identité managée :

    ```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` et `oid` sont l'ID d'objet de l'identité managée, `aud` est l'ID client de l'inscription d'application d'audience, et `azp` est l'ID client de l'identité managée (la valeur de `AZURE_CLIENT_ID`). La durée de vie diffère du parcours par identité managée : les jetons `client_credentials` ont par défaut une fenêtre aléatoire de 60 à 90 minutes entre `iat` et `exp`, et non 24 heures.
  </Step>
</Steps>

### Configurer Anthropic

Dans la Claude Console, accédez à la page [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), cliquez sur **Connect workload** et sélectionnez la tuile **Microsoft Entra**. L'assistant vous guide dans l'enregistrement de l'émetteur, la création d'un compte de service et la création d'une règle de fédération.

L'assistant crée ces ressources pour vous. Utilisez les valeurs suivantes, que vous les saisissiez dans l'assistant ou que vous les envoyiez à l'[Admin API](https://platform.claude.com/docs/fr/manage-claude/wif-admin-api) :

**Émetteur de fédération :** choisissez **v2.0 (login.microsoftonline.com)** dans le sélecteur **Token issuer** de l'assistant. (Le sélecteur est défini par défaut sur v1 ; cette valeur par défaut existe pour les locataires qui réutilisent d'anciennes inscriptions émettant encore des jetons v1.0.) Entra publie un document de découverte OIDC à l'URL d'émetteur propre au locataire ; utilisez donc le mode découverte. Chaque locataire Microsoft Entra que vous fédérez nécessite son propre enregistrement d'émetteur.

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

<Warning>
  La tuile Microsoft Entra de l'assistant Connect workload crée l'émetteur avec `max_jwt_lifetime_seconds` défini sur `7500` (un peu plus de 2 heures), ce qui couvre la durée de vie par défaut de 60 à 90 minutes des jetons `client_credentials`. Une stratégie de durée de vie des jetons du locataire ou la Continuous Access Evaluation (CAE) peut prolonger cette durée de vie. Si la différence `exp` moins `iat` de votre jeton décodé dépasse 7500 secondes, modifiez l'émetteur dans l'onglet **Issuers** de la page [Workload identity](https://platform.claude.com/settings/workload-identity-federation) de la Claude Console et augmentez `max_jwt_lifetime_seconds` en conséquence, faute de quoi les échanges échouent avec la réponse opaque `401` `authentication_error` (message `Authentication failed`). Si votre locataire exécute également des charges de travail à identité managée décrites dans [Utiliser une identité managée](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#use-a-managed-identity), utilisez la valeur `86400` de cette section, qui couvre les deux parcours.
</Warning>

Une durée de vie acceptée plus longue signifie qu'un jeton Entra divulgué reste échangeable plus longtemps. Si un jeton est divulgué, le levier consiste à désactiver la règle de fédération ; une correspondance stricte sur `oid` limite en premier lieu les identités pouvant échanger un jeton, comme décrit dans [Délimiter votre règle](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#scope-your-rule).

**Règle de fédération :** effectuez la correspondance sur l'ID d'objet de l'identité managée et l'ID de votre locataire. Pour les jetons v2.0 que ce guide configure, la valeur `audience` est l'ID client de l'inscription d'application d'audience (le GUID `<APP_ID>` de [Enregistrer l'audience du jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#register-the-token-audience)). Utilisez la valeur `aud` exacte de votre jeton décodé.

```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` est la durée de vie du jeton d'accès Anthropic renvoyé par l'échange, et non celle du jeton Entra ; le SDK le renouvelle pour vous.

### Acquérir et utiliser le jeton

À l'exécution, le pod effectue l'échange en deux étapes : il envoie le jeton projeté par Kubernetes (le fichier situé à `AZURE_FEDERATED_TOKEN_FILE`) au point de terminaison de jeton d'Entra en tant qu'assertion `client_credentials` fédérée, puis échange le jeton d'accès Entra obtenu sur `POST /v1/oauth/token`. Le SDK Claude gère le second échange et la boucle de renouvellement lorsque vous fournissez `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), comme le montrent les exemples suivants. Sauf en Java (voir le commentaire dans cet exemple), cette option accepte votre récupération Entra comme fournisseur de jetons, et le SDK l'appelle à nouveau à chaque renouvellement. L'onglet cURL présente le flux brut.

Deux ID client différents apparaissent dans les exemples. `<APP_ID>` est l'ID client de l'inscription d'application d'audience de [Enregistrer l'audience du jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#register-the-token-audience) ; la portée `api://<APP_ID>/.default` demande à Entra un jeton adressé à cette audience. `$AZURE_CLIENT_ID` est l'ID client de l'identité managée, injecté par le webhook, et identifie l'appelant. Ne substituez pas l'un à l'autre.

<Tip>
  Si votre charge de travail utilise déjà la bibliothèque cliente Azure Identity, obtenez le jeton Entra à partir de celle-ci (`DefaultAzureCredential` avec la portée `api://<APP_ID>/.default`) au lieu d'effectuer vous-même l'échange en deux étapes. Fournissez-le à `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) comme le font les exemples. La bibliothèque lit les mêmes variables d'environnement `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` et `AZURE_TENANT_ID` et gère l'échange Entra.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Échangez le jeton projeté par Kubernetes (dans $AZURE_FEDERATED_TOKEN_FILE)
  #    contre un JWT émis par 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. Échangez le JWT Entra contre un jeton d'accès 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. Appelez l'API 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();

      // Le SDK Java accepte le jeton lui-même ou un chemin de fichier, pas une fonction ; avec
      // source("value"), path(...) contient le jeton. Le SDK envoie ce même jeton
      // à chaque actualisation du jeton d'accès Anthropic, ce qui échoue dès qu'il a
      // expiré ou, s'il possède une revendication jti, été utilisé. Pour un processus
      // de longue durée, passez source("file") et écrivez un nouveau jeton dans le fichier avant
      // chaque actualisation.
      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. Échangez le jeton projeté par Kubernetes contre un jeton d'accès émis par Entra
  # et écrivez-le dans un fichier temporaire lisible par la CLI.
  ANTHROPIC_IDENTITY_TOKEN_FILE=$(mktemp)
  trap 'rm -f "$ANTHROPIC_IDENTITY_TOKEN_FILE"' EXIT
  curl -sS "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \
    -d client_id="$AZURE_CLIENT_ID" \
    -d grant_type=client_credentials \
    --data-urlencode "scope=api://<APP_ID>/.default" \
    -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
    --data-urlencode client_assertion@"$AZURE_FEDERATED_TOKEN_FILE" \
    | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
  export ANTHROPIC_IDENTITY_TOKEN_FILE

  # 2. Appelez l'API Claude. ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID et ANTHROPIC_WORKSPACE_ID sont lus
  # depuis l'environnement.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### Vérifier la configuration

Depuis un pod étiqueté, exécutez l'échange cURL présenté dans [Acquérir et utiliser le jeton](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) et vérifiez que `POST /v1/oauth/token` renvoie un `200` avec un `access_token` commençant par `sk-ant-oat01-` et une valeur `expires_in` en secondes. Si l'échange échoue avec la réponse opaque `401` `authentication_error` (message `Authentication failed`), consultez la [page d'historique d'authentification](https://platform.claude.com/settings/workload-identity-federation?tab=history) dans la Claude Console pour connaître le motif du refus, puis décodez le jeton émis par Entra à l'étape 1 (consultez [Dépanner un échange échoué](https://platform.claude.com/docs/fr/manage-claude/wif-reference#troubleshoot-a-failed-exchange) pour la commande) et vérifiez les causes les plus courantes côté Azure :

* **Non-concordance de l'émetteur :** l'`issuer_url` enregistrée doit correspondre exactement à la revendication `iss` du jeton. Un jeton v2.0 contient `https://login.microsoftonline.com/<TENANT_ID>/v2.0` ; si la revendication `ver` décodée vaut `1.0`, consultez [Si vos jetons sont en v1.0](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Durée de vie du jeton :** si une stratégie de durée de vie des jetons du locataire ou la CAE prolonge le jeton `client_credentials` au-delà de 7500 secondes, augmentez le `max_jwt_lifetime_seconds` de l'émetteur comme décrit dans [Configurer Anthropic](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#configure-anthropic-2).
* **Non-concordance de l'audience :** l'`audience` de la règle doit être exactement égale à l'`aud` du jeton : l'ID client de l'inscription d'application d'audience pour les jetons v2.0 que ce guide configure.
* **Non-concordance du nom de revendication :** une règle qui effectue la correspondance sur une revendication absente du jeton ne passe jamais. Les jetons v1.0 contiennent l'ID client dans `appid`, et non dans `azp` ; consultez [Si vos jetons sont en v1.0](https://platform.claude.com/docs/fr/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Si vos jetons sont en v1.0

Ce guide configure l'inscription d'application d'audience avec `api.requestedAccessTokenVersion: 2`, de sorte que chaque jeton qu'il présente est en v2.0. Si vous réutilisez une inscription existante qui laisse `requestedAccessTokenVersion` non défini, Entra émet des jetons v1.0 à la place. Décodez un exemple de jeton et vérifiez sa revendication `ver` ; si elle vaut `1.0`, quatre éléments changent :

* **Émetteur :** la revendication `iss` est `https://sts.windows.net/<TENANT_ID>/` au lieu de `https://login.microsoftonline.com/<TENANT_ID>/v2.0`. Enregistrez l'URL de l'émetteur exactement telle qu'elle figure dans la revendication `iss` de votre jeton. Les deux URL partagent le même JWKS, le mode découverte fonctionne donc pour l'une comme pour l'autre.
* **Sélecteur de l'assistant :** choisissez **v1 (sts.windows.net)** dans le sélecteur **Token issuer** de l'assistant Connect workload au lieu de **v2.0 (login.microsoftonline.com)**.
* **Audience :** la revendication `aud` est l'URI d'identifiant que vous avez transmise comme `resource` (par exemple, `api://<APP_ID>`), et non l'ID client de l'inscription. Définissez l'`audience` de la règle de fédération sur la valeur `aud` exacte de votre jeton décodé.
* **Revendication d'ID client :** l'ID client de l'identité appelante apparaît dans `appid`, et non dans `azp`. Les deux revendications n'apparaissent jamais dans le même jeton ; une règle qui effectue la correspondance sur `azp` ne passe donc jamais avec un jeton v1.0.

Les revendications `oid`, `sub` et `tid` contiennent les mêmes valeurs dans les deux versions, le reste de ce guide s'applique donc sans modification.

## Délimiter votre règle

Une règle de fédération peut effectuer la correspondance sur le sujet du jeton avec `subject_prefix` en plus (ou à la place) de la table `claims` ; consultez [Sémantique de correspondance des règles](https://platform.claude.com/docs/fr/manage-claude/wif-reference#rule-matching-semantics) pour savoir comment les champs se combinent. Les valeurs `sub` d'Entra pour ces identités sont des GUID canoniques de longueur fixe ; un `subject_prefix` contenant l'ID d'objet complet de 36 caractères ne correspond donc qu'à ce sujet. Il s'agit d'une propriété du format de sujet d'Entra, et non de `subject_prefix` en général.

<Warning>
  Chaque identité de votre locataire peut demander un jeton pour l'audience enregistrée ; `audience` et `tid` seuls n'identifient donc pas une charge de travail spécifique. Une règle qui omet une correspondance sur `oid` (ou `azp`/`appid`), ou qui utilise un `subject_prefix` générique ou à GUID partiel, autorise chaque identité managée et chaque principal de service du locataire.
</Warning>

Verrouillez le bloc `match` de la règle sur la portée la plus étroite qui convient à votre cas d'usage :

* **Faire correspondre `oid` comme valeur exacte :** définissez `claims.oid` sur l'ID d'objet complet de l'identité managée. Un `subject_prefix` défini sur cet ID d'objet complet est équivalent (l'assistant de la Console définit les deux) ; n'utilisez jamais un `subject_prefix` générique ou à GUID partiel, qui correspond à plus d'identités que vous ne le souhaitez.
* **Fixer `tid` comme défense en profondeur :** l'URL de l'émetteur fixe déjà votre locataire, mais l'ajout de `claims.tid` protège contre une dérive de configuration si l'enregistrement de l'émetteur est modifié ultérieurement.
* **Fixer l'audience :** définissez `audience` sur la valeur `aud` exacte de votre jeton décodé afin que les jetons émis pour d'autres applications soient rejetés.
* **Utiliser une règle distincte pour chaque identité managée :** créez une règle pour chaque identité plutôt qu'une seule règle qui en autorise plusieurs, afin de pouvoir révoquer l'accès d'une seule charge de travail sans affecter les autres.

## Étapes suivantes

* Consultez le modèle de configuration complet dans [Workload Identity Federation](https://platform.claude.com/docs/fr/manage-claude/workload-identity-federation).
* Consultez les [guides des fournisseurs](https://platform.claude.com/docs/fr/manage-claude/workload-identity-federation#identity-providers) pour AWS, Google Cloud, GitHub Actions et Kubernetes.
* Pour les variables d'environnement, les fichiers de profil et la priorité des informations d'identification, consultez la [référence WIF](https://platform.claude.com/docs/fr/manage-claude/wif-reference).
