---
title: WIF mit Microsoft Entra ID verwenden
url: https://platform.claude.com/docs/de/manage-claude/wif-providers/azure
description: Föderiere verwaltete Azure-Identitäten und Entra Workload Identity mit der Claude API, damit deine Azure-Workloads Claude ohne statische API-Keys aufrufen können.
---

Azure-Workloads authentifizieren sich bei der Claude API, indem sie ein von Microsoft Entra ID ausgestelltes „JSON Web Token“, oder JWT, vorlegen und es anschließend gegen ein kurzlebiges Anthropic-Zugriffstoken („access token“) eintauschen. Die Einrichtung folgt auf jeder Azure-Plattform demselben Muster:

1. **Token-Audience registrieren:** Erstelle eine „app registration“ (App-Registrierung) in deinem Microsoft-Entra-„tenant“ (Mandanten), die die „audience“ (Zielgruppe) der Claude API repräsentiert. Jeder Workload im Mandanten fordert Entra-Token für sie an.
2. **Identität für deine Plattform einrichten:** Eine „managed identity“ (verwaltete Identität) auf VMs, VM Scale Sets, App Service, Functions und Container Apps oder Entra Workload Identity auf AKS.
3. **Anthropic konfigurieren:** Registriere den Entra-„issuer“ (Aussteller) deines Mandanten, erstelle einen „service account“ (Dienstkonto) und schreibe eine „federation rule“ (Föderationsregel), die zu den „claims“ (Ansprüchen) des Tokens passt.
4. **Zur Laufzeit austauschen:** Dein Workload tauscht sein von Entra ausgestelltes Token bei `POST /v1/oauth/token` gegen ein `sk-ant-oat01-...`-Anthropic-Zugriffstoken ein und ruft Claude damit auf.

Auf beiden Wegen trägt das Token, das du Anthropic vorlegst, deinen mandantenspezifischen Entra-Issuer sowie die Objekt-ID der verwalteten Identität in den Claims `sub` und `oid`; nur die Art, wie der Workload dieses Token erhält, unterscheidet sich. Wähle den Abschnitt, der dem Ausführungsort deines Workloads entspricht: [Eine verwaltete Identität verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#use-a-managed-identity) für VMs, VM Scale Sets, App Service, Functions oder Container Apps; [Entra Workload Identity auf AKS verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#use-entra-workload-identity-on-aks) für AKS.

## Voraussetzungen

* Vertrautheit mit den [WIF-Konzepten](https://platform.claude.com/docs/de/manage-claude/workload-identity-federation#concepts): Dienstkonten, Föderations-Issuer und Föderationsregeln.
* Ein Azure-Abonnement mit der Berechtigung, verwaltete Identitäten zuzuweisen (oder Entra Workload Identity auf AKS zu konfigurieren).
* Die Berechtigung, eine App-Registrierung und einen „service principal“ (Dienstprinzipal) in deinem Microsoft-Entra-Mandanten zu erstellen (die gemeinsame Claude-API-Audience). Entra stellt Token nur für eine Audience aus, die im Mandanten existiert, daher ist der Schritt [Token-Audience registrieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#register-the-token-audience) erforderlich, bevor irgendeine Token-Anforderung erfolgreich ist.
* Deine Microsoft-Entra-Mandanten-ID. Du findest sie im Azure-Portal unter **Microsoft Entra ID → Overview → Tenant ID**.
* Die Berechtigung, in der Claude Console Dienstkonten, Föderations-Issuer und Föderationsregeln für deine Anthropic-Organisation zu erstellen.

## Token-Audience registrieren

Microsoft Entra ID stellt ein Token nur aus, wenn die angeforderte Audience in deinem Mandanten als App-Registrierung mit einem Dienstprinzipal existiert. Erstelle eine App-Registrierung, die die Claude-API-Audience repräsentiert; jeder Workload im Mandanten kann Token für sie anfordern. Ohne diese Registrierung schlagen Token-Anforderungen mit einem Fehler „resource not found in tenant“ fehl (`AADSTS50001` von den Endpunkten der verwalteten Identität, `AADSTS500011` vom Entra-Token-Endpunkt).

```bash
# Erstelle die App-Registrierung, die die Claude API-Audience repräsentiert.
APP_ID=$(az ad app create --display-name claude-api-federation --query appId -o tsv)

# Fordere v2.0-Zugriffstoken an und setze die Bezeichner-URI api://<APP_ID>.
az ad app update --id "$APP_ID" \
  --identifier-uris "api://$APP_ID" \
  --set api.requestedAccessTokenVersion=2

# Erstelle den Dienstprinzipal, damit die Audience in deinem Mandanten aufgelöst wird.
az ad sp create --id "$APP_ID"
```

<Note>
  Verwende das Bezeichner-URI-Format `api://<APP_ID>`. Entra beschränkt `https://`-Bezeichner-URIs auf verifizierte Domänen deines eigenen Mandanten, sodass eine URI wie `https://api.anthropic.com` in den meisten Mandanten nicht registriert werden kann; `api://<APP_ID>` wird überall akzeptiert. Mit `requestedAccessTokenVersion: 2` sind Token für diese Audience v2.0, wovon dieser Leitfaden ausgeht. Wenn du eine bestehende Registrierung wiederverwendest, die v1.0-Token ausgibt, siehe [Wenn deine Token v1.0 sind](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
</Note>

## Eine verwaltete Identität verwenden

Verwende diesen Weg, wenn dein Workload auf einer VM, einem VM Scale Set, App Service, Functions oder Container Apps läuft. Der Workload fordert vom lokalen Token-Endpunkt der Plattform ein von Entra ausgestelltes JWT für seine zugewiesene verwaltete Identität an und tauscht dieses JWT dann bei Anthropic ein.

### Die verwaltete Identität konfigurieren

<Steps>
  <Step title="Eine verwaltete Identität anhängen">
    Aktiviere eine systemseitig oder benutzerseitig zugewiesene verwaltete Identität auf deiner Azure-Ressource. Öffne im Azure-Portal die Ressource, gehe zu **Identity** und schalte **System assigned** ein (oder hänge eine benutzerseitig zugewiesene Identität an).

    Notiere nach dem Erstellen der Identität ihre **Object (principal) ID**. Diese GUID erscheint im ausgestellten Token sowohl als `sub`- als auch als `oid`-Claim, und deine Anthropic-Föderationsregel wird darauf abgleichen. Du findest sie auf der Seite **Identity** der Ressource; bei einer benutzerseitig zugewiesenen Identität ist es die **Object (principal) ID** auf der Seite **Overview** der Ressource der verwalteten Identität. (Eine verwaltete Identität hat in Microsoft Entra ID nur einen Dienstprinzipal, keine App-Registrierung.)
  </Step>

  <Step title="Den Token-Endpunkt der Plattform finden">
    Die Plattform stellt einen lokalen Token-Endpunkt bereit, sobald die Identität angehängt ist:

    * **VMs und VM Scale Sets:** IMDS unter `http://169.254.169.254/metadata/identity/oauth2/token` mit dem Header `Metadata: true` und `api-version=2018-02-01`.
    * **App Service, Functions und Container Apps:** Die URL in der Umgebungsvariablen `IDENTITY_ENDPOINT` mit dem Header `X-IDENTITY-HEADER`, gesetzt auf den Wert von `IDENTITY_HEADER`, und `api-version=2019-08-01`. IMDS ist auf diesen Plattformen nicht erreichbar.

    Wenn die Ressource mehr als eine benutzerseitig zugewiesene verwaltete Identität hat, füge der Token-Anforderung `client_id=<IDENTITY_CLIENT_ID>` hinzu, um eine auszuwählen. Azure empfiehlt, sie immer anzugeben. Ohne sie hängt das Ergebnis davon ab, ob auf der Ressource zusätzlich eine systemseitig zugewiesene Identität aktiviert ist: Falls ja, fällt die Anforderung stillschweigend auf diese Identität zurück und scheitert dann am `oid`-Abgleich deiner Föderationsregel; falls nein, schlägt die Anforderung sofort fehl, sobald eine zweite benutzerseitig zugewiesene Identität angehängt wird.
  </Step>

  <Step title="Ein Beispiel-Token dekodieren">
    Fordere ein Token vom Endpunkt an und dekodiere seine Payload, um die Claims zu bestätigen, auf die deine Föderationsregel abgleichen muss. (Den Dekodierbefehl findest du unter [Fehlerbehebung bei einem fehlgeschlagenen Austausch](https://platform.claude.com/docs/de/manage-claude/wif-reference#troubleshoot-a-failed-exchange).) Ein v2.0-Token für eine verwaltete Identität trägt diese Claims:

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

    | Claim | Wert                                                                                                                                                                                                    | Gleiche darauf ab, wenn                                                                                                                                                                                                                   |
    | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `oid` | Die Objekt-ID der verwalteten Identität, identisch mit `sub`                                                                                                                                            | Du eine bestimmte verwaltete Identität autorisieren möchtest. Dies ist der Standard; die Regel in [Anthropic konfigurieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#configure-anthropic) gleicht darauf ab. |
    | `azp` | Die Client-ID der aufrufenden Identität                                                                                                                                                                 | Du jeden Workload autorisieren möchtest, der sich eine App-Registrierung teilt. Bei einer verwalteten Identität ist `azp` für diese Identität eindeutig und damit äquivalent zu `oid`.                                                    |
    | `aud` | Die Client-ID der Audience-App-Registrierung (die `<APP_ID>`-GUID aus [Token-Audience registrieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#register-the-token-audience)) | Immer. Das Feld `audience` der Regel muss exakt dem `aud`-Wert des Tokens entsprechen.                                                                                                                                                    |
    | `tid` | Deine Mandanten-ID                                                                                                                                                                                      | Du „defense in depth“ (mehrschichtige Absicherung) möchtest. Die Issuer-URL legt den Mandanten bereits fest.                                                                                                                              |

    Wenn der `ver`-Claim des dekodierten Tokens `1.0` ist, unterscheiden sich die Claim-Namen und -Werte. Siehe [Wenn deine Token v1.0 sind](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0), bevor du fortfährst.
  </Step>
</Steps>

### Anthropic konfigurieren

Gehe in der Claude Console zur Seite [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), klicke auf **Connect workload** und wähle die Kachel **Microsoft Entra**. Der Assistent führt dich durch das Registrieren des Issuers, das Erstellen eines Dienstkontos und das Erstellen einer Föderationsregel.

Der Assistent erstellt diese Ressourcen für dich. Verwende die folgenden Werte, unabhängig davon, ob du sie im Assistenten eingibst oder an die [Admin API](https://platform.claude.com/docs/de/manage-claude/wif-admin-api) sendest:

**Föderations-Issuer:** Wähle **v2.0 (login.microsoftonline.com)** in der Auswahl **Token issuer** des Assistenten. (Die Auswahl steht standardmäßig auf v1; dieser Standard existiert für Mandanten, die ältere Registrierungen wiederverwenden, die noch v1.0-Token ausgeben.) Entra veröffentlicht ein OIDC-Discovery-Dokument unter der mandantenspezifischen Issuer-URL, verwende also den Discovery-Modus. Jeder Microsoft-Entra-Mandant, den du föderierst, benötigt einen eigenen Issuer-Eintrag.

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

<Warning>
  Workloads mit verwalteter Identität benötigen `max_jwt_lifetime_seconds: 86400`. Azure stellt Token für verwaltete Identitäten mit bis zu 24 Stunden zwischen `iat` und `exp` aus, weil es das Token jeder Ressource für dieses Zeitfenster zwischenspeichert und keine Möglichkeit bietet, eine vorzeitige Aktualisierung zu erzwingen. Der 1-Stunden-Standard des Issuers lehnt diese Token ab, sodass der Austausch mit der undurchsichtigen `401`-`authentication_error`-Antwort (Meldung `Authentication failed`) fehlschlägt. Die Microsoft-Entra-Kachel des Assistenten „Connect workload“ erstellt den Issuer mit `max_jwt_lifetime_seconds` auf `7500` gesetzt und bietet während der Erstellung kein Feld, um dies zu ändern. Schließe daher den Assistenten ab, öffne dann in der Claude Console auf der Seite [Workload identity](https://platform.claude.com/settings/workload-identity-federation) den Tab **Issuers**, bearbeite den Issuer und erhöhe den Wert auf `86400`. Du kannst den Issuer auch über die Admin API aktualisieren.
</Warning>

Eine längere akzeptierte Lebensdauer bedeutet, dass ein geleaktes Entra-Token länger eintauschbar bleibt. Wenn ein Token leakt, ist der Hebel das Deaktivieren der Föderationsregel; ein enger `oid`-Abgleich begrenzt von vornherein, welche Identitäten ein Token eintauschen können, wie in [Deine Regel eingrenzen](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#scope-your-rule) beschrieben.

**Föderationsregel:** Gleiche auf die Objekt-ID der verwalteten Identität und deine Mandanten-ID ab. Für die v2.0-Token, die dieser Leitfaden konfiguriert, ist der `audience`-Wert die Client-ID der Audience-App-Registrierung (die `<APP_ID>`-GUID aus [Token-Audience registrieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#register-the-token-audience)). Verwende den exakten `aud`-Wert aus deinem dekodierten Token.

```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` ist die Lebensdauer des Anthropic-Zugriffstokens, das der Austausch zurückgibt, nicht die des Entra-Tokens; das SDK aktualisiert es für dich.

### Das Token beziehen und verwenden

Zur Laufzeit ruft dein Workload sein Entra-Token ab, tauscht es bei `POST /v1/oauth/token` ein und verwendet das zurückgegebene Bearer-Token, um Claude aufzurufen. Das Claude SDK übernimmt den Austausch und die Aktualisierungsschleife, wenn du `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) angibst, wie in den folgenden Beispielen gezeigt. Außer in Java (siehe den Kommentar im Java-Beispiel) nimmt diese Option einen Token-Provider entgegen, und das SDK ruft ihn bei jeder Aktualisierung erneut auf. Der cURL-Tab zeigt den rohen Ablauf.

Die Beispiele rufen das Token der verwalteten Identität vom Token-Endpunkt der Plattform ab: IMDS auf VMs und VM Scale Sets oder der `IDENTITY_ENDPOINT`-Dienst auf App Service, Functions und Container Apps. Ersetze `<APP_ID>` im Ressourcenwert `api://<APP_ID>` durch die Client-ID der Audience-App-Registrierung aus [Token-Audience registrieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#register-the-token-audience).

<Tip>
  Wenn dein Workload bereits die Azure-Identity-Clientbibliothek verwendet, hole das Entra-Token darüber (`DefaultAzureCredential` mit dem Scope `api://<APP_ID>/.default`), anstatt die Token-Endpunkte direkt aufzurufen. Übergib es an `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), so wie es die Beispiele tun. Die Bibliothek wählt auf jeder Azure-Plattform den richtigen Endpunkt aus, einschließlich AKS mit Entra Workload Identity.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Hole das von Entra ausgestellte Token (Managed Identity).
  #    Verwende auf einer VM oder einem VM Scale Set IMDS. Bei mehreren benutzerzugewiesenen
  #    Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
  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)

  #    Verwende auf App Service, Functions oder Container Apps stattdessen den lokalen Token-
  #    Dienst (IMDS ist dort nicht erreichbar):
  # 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)

  #    Verwende für AKS mit Entra Workload Identity stattdessen den zweistufigen Austausch im
  #    Abschnitt „Use Entra Workload Identity on AKS“.

  # 2. Tausche es gegen ein Anthropic-Zugriffstoken.
  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. Rufe die Claude API mit dem Bearer-Token auf.
  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

  # Die Identifier-URI der App-Registrierung für die Audience (siehe Token-Audience registrieren).
  AUDIENCE = "api://<APP_ID>"


  def fetch_entra_token() -> str:
      """Fetch a managed identity token from the platform's token endpoint."""
      # Bei mehreren benutzerseitig zugewiesenen Identitäten füge client_id=<IDENTITY_CLIENT_ID>
      # zu den Request-Parametern hinzu, um eine auszuwählen.
      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 oder 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";

  // Die Bezeichner-URI der App-Registrierung für die Zielgruppe (siehe Register the token audience).
  const AUDIENCE = "api://<APP_ID>";

  async function fetchEntraToken(): Promise<string> {
    // App Service, Functions und Container Apps injizieren IDENTITY_ENDPOINT;
    // VMs und VM Scale Sets verwenden IMDS.
    // Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
    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"
  )

  // Die Identifier-URI der Audience-App-Registrierung (siehe Register the token audience).
  const audience = "api://<APP_ID>"

  // fetchEntraToken ruft ein Managed-Identity-Token vom Token-Endpunkt der Plattform ab:
  // IMDS auf VMs und VM Scale Sets bzw. den IDENTITY_ENDPOINT-Dienst
  // auf App Service, Functions und Container Apps.
  func fetchEntraToken(ctx context.Context) (string, error) {
  	// Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
  	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();
      // Der Bezeichner-URI der App-Registrierung für die Zielgruppe (siehe Register the token audience).
      String audience = "api://<APP_ID>";
      // App Service, Functions und Container Apps injizieren IDENTITY_ENDPOINT;
      // VMs und VM Scale Sets verwenden IMDS.
      // Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
      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();

      // Das Java SDK nimmt das Token selbst oder einen Dateipfad, keine Funktion; mit
      // source("value") enthält path(...) das Token. Das SDK sendet dasselbe Token
      // bei jeder Aktualisierung des Anthropic-Zugriffstokens, was fehlschlägt, sobald es
      // abgelaufen ist oder, falls es einen jti-Claim hat, bereits verwendet wurde. Für länger laufende
      // Prozesse übergib source("file") und schreibe vor jeder Aktualisierung ein neues Token
      // in die Datei.
      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
  {
      // Die Identifier-URI der Audience-App-Registrierung (siehe 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 und Container Apps injizieren IDENTITY_ENDPOINT;
          // VMs und VM Scale Sets verwenden IMDS.
          // Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
          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;

  // Die Identifier-URI der Audience-App-Registrierung (siehe Register the token audience).
  const AUDIENCE = 'api://<APP_ID>';

  class EntraIdentityToken implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          // App Service, Functions und Container Apps injizieren IDENTITY_ENDPOINT;
          // VMs und VM Scale Sets verwenden IMDS.
          // Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
          $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"

  # Die Identifier-URI der App-Registrierung für die Audience (siehe Register the token audience).
  AUDIENCE = "api://<APP_ID>"

  def fetch_entra_token
    # App Service, Functions und Container Apps injizieren IDENTITY_ENDPOINT;
    # VMs und VM Scale Sets verwenden IMDS.
    # Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
    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
  # Schreibe das von Entra ausgestellte Access-Token in eine Datei, die die CLI lesen kann.
  # Gezeigt für eine VM oder ein VM Scale Set (IMDS). Bei App Service, Functions oder
  # Container Apps rufst du stattdessen "$IDENTITY_ENDPOINT?api-version=2019-08-01&resource=api://<APP_ID>" ab,
  # und zwar mit -H "X-IDENTITY-HEADER: $IDENTITY_HEADER".
  # Bei mehreren benutzerseitig zugewiesenen Identitäten hänge &client_id=<IDENTITY_CLIENT_ID> an.
  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 und ANTHROPIC_WORKSPACE_ID werden aus der Umgebung gelesen.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### Die Einrichtung überprüfen

Führe von deiner Azure-Ressource aus den in [Das Token beziehen und verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#acquire-and-use-the-token) gezeigten cURL-Austausch aus und bestätige, dass `POST /v1/oauth/token` ein `200` mit einem `access_token`, das mit `sk-ant-oat01-` beginnt, und einem `expires_in`-Wert in Sekunden zurückgibt. Wenn der Austausch mit der undurchsichtigen `401`-`authentication_error`-Antwort (Meldung `Authentication failed`) fehlschlägt, prüfe auf der [Seite mit dem Authentifizierungsverlauf](https://platform.claude.com/settings/workload-identity-federation?tab=history) in der Claude Console den Ablehnungsgrund, dekodiere dann das Entra-Token (den Befehl findest du unter [Fehlerbehebung bei einem fehlgeschlagenen Austausch](https://platform.claude.com/docs/de/manage-claude/wif-reference#troubleshoot-a-failed-exchange)) und prüfe die häufigsten Ursachen auf Azure-Seite:

* **Issuer-Abweichung:** Die registrierte `issuer_url` muss exakt mit dem `iss`-Claim des Tokens übereinstimmen. Ein v2.0-Token trägt `https://login.microsoftonline.com/<TENANT_ID>/v2.0`; wenn der dekodierte `ver`-Claim `1.0` ist, siehe [Wenn deine Token v1.0 sind](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Token-Lebensdauer:** Token für verwaltete Identitäten tragen bis zu 24 Stunden zwischen `iat` und `exp`. Wenn der Issuer noch den Wert `7500` des Assistenten (oder den 1-Stunden-Standard) hat, erhöhe `max_jwt_lifetime_seconds` auf `86400`, wie in [Anthropic konfigurieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#configure-anthropic) beschrieben.
* **Audience-Abweichung:** Die `audience` der Regel muss exakt dem `aud` des Tokens entsprechen: der Client-ID der Audience-App-Registrierung für die v2.0-Token, die dieser Leitfaden konfiguriert.
* **Claim-Namen-Abweichung:** Eine Regel, die auf einen Claim abgleicht, den das Token nicht trägt, besteht nie. v1.0-Token tragen die Client-ID in `appid`, nicht in `azp`; siehe [Wenn deine Token v1.0 sind](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Entra Workload Identity auf AKS verwenden

Verwende diesen Weg, wenn dein Workload in einem AKS-Pod läuft. Entra Workload Identity föderiert ein Kubernetes-Dienstkonto mit einer benutzerseitig zugewiesenen verwalteten Identität: Kubernetes projiziert ein Dienstkonto-Token (signiert vom OIDC-Issuer des AKS-Clusters) in den Pod unter dem Pfad in `AZURE_FEDERATED_TOKEN_FILE`. Dieses projizierte Token ist kein von Entra ausgestelltes Token. Um auf dem auf dieser Seite beschriebenen, über Entra vermittelten Weg zu bleiben, führt der Workload daher einen zweistufigen Austausch durch: Er löst zuerst das projizierte Token bei `https://login.microsoftonline.com/<TENANT_ID>/oauth2/v2.0/token` (föderierter `client_credentials`-Grant) gegen ein von Entra ausgestelltes Zugriffstoken ein und übergibt dann dieses Entra-Token als Identity-Token an das Anthropic SDK.

<Tip>
  AKS-Pods können alternativ den Entra-Austausch überspringen und das von Kubernetes projizierte Dienstkonto-Token direkt bei Anthropic vorlegen. Dieser Weg registriert den OIDC-Issuer deines AKS-Clusters bei Anthropic anstelle deines Entra-Mandanten. Siehe [WIF mit Kubernetes verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/kubernetes) für diesen Ablauf.
</Tip>

### Entra Workload Identity konfigurieren

<Steps>
  <Step title="Den OIDC-Issuer und Workload Identity auf deinem Cluster aktivieren">
    Das Aktivieren von Workload Identity installiert den Mutating Webhook `azure-workload-identity` für dich; stelle ihn nur auf Nicht-AKS-Clustern manuell bereit. Erfasse die OIDC-Issuer-URL des Clusters für die föderierten Anmeldeinformationen, die du in einem späteren Schritt erstellst.

    ```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="Eine benutzerseitig zugewiesene verwaltete Identität erstellen">
    Erfasse zwei Werte der Identität: Die **Client ID** kommt in die Annotation des Dienstkontos (und wird als `AZURE_CLIENT_ID` in den Pod injiziert), und die **Object (principal) ID** erscheint als `oid`-Claim, auf den deine Anthropic-Föderationsregel abgleicht.

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

    # Gehört in die Service-Account-Annotation; wird als AZURE_CLIENT_ID in den Pod injiziert.
    IDENTITY_CLIENT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query clientId -o tsv)

    # Erscheint als oid-Claim, auf den deine Föderationsregel matcht.
    IDENTITY_OBJECT_ID=$(az identity show \
      --resource-group <RESOURCE_GROUP> \
      --name claude-inference-identity \
      --query principalId -o tsv)
    ```
  </Step>

  <Step title="Das annotierte Kubernetes-Dienstkonto erstellen">
    Der Webhook `azure-workload-identity` liest die Annotation `azure.workload.identity/client-id`, um `AZURE_CLIENT_ID` in den Pod zu injizieren, was die Beispiele in [Das Token beziehen und verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) aus der Umgebung lesen.

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

  <Step title="Die föderierten Anmeldeinformationen auf der verwalteten Identität erstellen">
    Die „federated credential“ (föderierten Anmeldeinformationen) vertrauen dem OIDC-Issuer deines Clusters für dieses spezifische Dienstkonto. Der Wert `--audience api://AzureADTokenExchange` ist Entras feste Audience für eingehende Kubernetes-Dienstkonto-Token; er hat nichts mit der Claude-API-Audience zu tun, die du zuvor registriert hast.

    ```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="Den Pod labeln und sein Dienstkonto setzen">
    Der Pod muss das Label `azure.workload.identity/use: "true"` tragen und als das annotierte Dienstkonto laufen. Der Webhook injiziert dann `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` und `AZURE_TENANT_ID` in den Pod. Die Datei unter `AZURE_FEDERATED_TOKEN_FILE` enthält das von Kubernetes projizierte Dienstkonto-Token, signiert vom OIDC-Issuer des AKS-Clusters.

    ```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="Ein Beispiel-Token dekodieren">
    Das Token, das deine Anthropic-Föderationsregel sieht, ist nicht die projizierte Datei; es ist das von Entra ausgestellte Token, das der `client_credentials`-Austausch zurückgibt. Führe aus einem gelabelten Pod heraus Schritt 1 des cURL-Beispiels in [Das Token beziehen und verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) aus und dekodiere das Ergebnis. Es trägt dieselbe Claim-Struktur wie der Weg mit verwalteter Identität:

    ```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` und `oid` sind die Objekt-ID der verwalteten Identität, `aud` ist die Client-ID der Audience-App-Registrierung und `azp` ist die Client-ID der verwalteten Identität (der Wert von `AZURE_CLIENT_ID`). Die Lebensdauer unterscheidet sich vom Weg mit verwalteter Identität: `client_credentials`-Token haben standardmäßig ein zufälliges Zeitfenster von 60 bis 90 Minuten zwischen `iat` und `exp`, nicht 24 Stunden.
  </Step>
</Steps>

### Anthropic konfigurieren

Gehe in der Claude Console zur Seite [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), klicke auf **Connect workload** und wähle die Kachel **Microsoft Entra**. Der Assistent führt dich durch das Registrieren des Issuers, das Erstellen eines Dienstkontos und das Erstellen einer Föderationsregel.

Der Assistent erstellt diese Ressourcen für dich. Verwende die folgenden Werte, unabhängig davon, ob du sie im Assistenten eingibst oder an die [Admin API](https://platform.claude.com/docs/de/manage-claude/wif-admin-api) sendest:

**Föderations-Issuer:** Wähle **v2.0 (login.microsoftonline.com)** in der Auswahl **Token issuer** des Assistenten. (Die Auswahl steht standardmäßig auf v1; dieser Standard existiert für Mandanten, die ältere Registrierungen wiederverwenden, die noch v1.0-Token ausgeben.) Entra veröffentlicht ein OIDC-Discovery-Dokument unter der mandantenspezifischen Issuer-URL, verwende also den Discovery-Modus. Jeder Microsoft-Entra-Mandant, den du föderierst, benötigt einen eigenen Issuer-Eintrag.

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

<Warning>
  Die Microsoft-Entra-Kachel des Assistenten „Connect workload“ erstellt den Issuer mit `max_jwt_lifetime_seconds` auf `7500` gesetzt (knapp über 2 Stunden), was die standardmäßige Lebensdauer von 60 bis 90 Minuten von `client_credentials`-Token abdeckt. Eine Token-Lebensdauer-Richtlinie des Mandanten oder Continuous Access Evaluation (CAE) kann diese Lebensdauer verlängern. Wenn bei deinem dekodierten Token `exp` minus `iat` 7500 Sekunden überschreitet, bearbeite den Issuer im Tab **Issuers** der Seite [Workload identity](https://platform.claude.com/settings/workload-identity-federation) in der Claude Console und erhöhe `max_jwt_lifetime_seconds` entsprechend, sonst schlagen Austausche mit der undurchsichtigen `401`-`authentication_error`-Antwort (Meldung `Authentication failed`) fehl. Wenn dein Mandant außerdem Workloads mit verwalteter Identität aus [Eine verwaltete Identität verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#use-a-managed-identity) betreibt, verwende den Wert `86400` aus jenem Abschnitt, der beide Wege abdeckt.
</Warning>

Eine längere akzeptierte Lebensdauer bedeutet, dass ein geleaktes Entra-Token länger eintauschbar bleibt. Wenn ein Token leakt, ist der Hebel das Deaktivieren der Föderationsregel; ein enger `oid`-Abgleich begrenzt von vornherein, welche Identitäten ein Token eintauschen können, wie in [Deine Regel eingrenzen](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#scope-your-rule) beschrieben.

**Föderationsregel:** Gleiche auf die Objekt-ID der verwalteten Identität und deine Mandanten-ID ab. Für die v2.0-Token, die dieser Leitfaden konfiguriert, ist der `audience`-Wert die Client-ID der Audience-App-Registrierung (die `<APP_ID>`-GUID aus [Token-Audience registrieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#register-the-token-audience)). Verwende den exakten `aud`-Wert aus deinem dekodierten Token.

```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` ist die Lebensdauer des Anthropic-Zugriffstokens, das der Austausch zurückgibt, nicht die des Entra-Tokens; das SDK aktualisiert es für dich.

### Das Token beziehen und verwenden

Zur Laufzeit führt der Pod den zweistufigen Austausch durch: Er sendet das von Kubernetes projizierte Token (die Datei unter `AZURE_FEDERATED_TOKEN_FILE`) als föderierte `client_credentials`-Assertion an den Token-Endpunkt von Entra und tauscht dann das resultierende Entra-Zugriffstoken bei `POST /v1/oauth/token` ein. Das Claude SDK übernimmt den zweiten Austausch und die Aktualisierungsschleife, wenn du `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`) angibst, wie in den folgenden Beispielen gezeigt. Außer in Java (siehe den Kommentar im Java-Beispiel) nimmt diese Option deinen Entra-Abruf als Token-Provider entgegen, und das SDK ruft ihn bei jeder Aktualisierung erneut auf. Der cURL-Tab zeigt den rohen Ablauf.

In den Beispielen erscheinen zwei verschiedene Client-IDs. `<APP_ID>` ist die Client-ID der Audience-App-Registrierung aus [Token-Audience registrieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#register-the-token-audience); der Scope `api://<APP_ID>/.default` fordert von Entra ein Token an, das an diese Audience adressiert ist. `$AZURE_CLIENT_ID` ist die Client-ID der verwalteten Identität, vom Webhook injiziert, und identifiziert den Aufrufer. Ersetze nicht die eine durch die andere.

<Tip>
  Wenn dein Workload bereits die Azure-Identity-Clientbibliothek verwendet, hole das Entra-Token darüber (`DefaultAzureCredential` mit dem Scope `api://<APP_ID>/.default`), anstatt den zweistufigen Austausch selbst durchzuführen. Übergib es an `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`), so wie es die Beispiele tun. Die Bibliothek liest dieselben Umgebungsvariablen `AZURE_FEDERATED_TOKEN_FILE`, `AZURE_CLIENT_ID` und `AZURE_TENANT_ID` und übernimmt den Entra-Austausch.
</Tip>

<CodeGroup>
  ```bash cURL
  # 1. Tausche das von Kubernetes projizierte Token (unter $AZURE_FEDERATED_TOKEN_FILE)
  #    gegen ein von Entra ausgestelltes JWT.
  ENTRA_JWT=$(curl -sS "https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token" \
    -d grant_type=client_credentials \
    -d "client_id=$AZURE_CLIENT_ID" \
    --data-urlencode "scope=api://<APP_ID>/.default" \
    -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
    --data-urlencode "client_assertion@$AZURE_FEDERATED_TOKEN_FILE" \
    | jq -r .access_token)

  # 2. Tausche das Entra-JWT gegen ein Anthropic-Zugriffstoken.
  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. Rufe die Claude API auf.
  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();

      // Das Java SDK nimmt das Token selbst oder einen Dateipfad, keine Funktion; mit
      // source("value") enthält path(...) das Token. Das SDK sendet dasselbe Token
      // bei jeder Aktualisierung des Anthropic-Zugriffstokens, was fehlschlägt, sobald es
      // abgelaufen ist oder, falls es einen jti-Claim hat, bereits verwendet wurde. Für länger laufende
      // Prozesse übergib source("file") und schreibe vor jeder Aktualisierung ein neues Token
      // in die Datei.
      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. Tausche das von Kubernetes projizierte Token gegen ein von Entra ausgestelltes Zugriffs-
  # Token und schreibe es in eine temporäre Datei, die die CLI lesen kann.
  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. Rufe die Claude API auf. ANTHROPIC_FEDERATION_RULE_ID,
  # ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID und ANTHROPIC_WORKSPACE_ID werden
  # aus der Umgebung gelesen.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello from Azure"}'
  ```
</CodeGroup>

### Die Einrichtung überprüfen

Führe innerhalb eines gelabelten Pods den in [Das Token beziehen und verwenden](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#acquire-and-use-the-token-2) gezeigten cURL-Austausch aus und bestätige, dass `POST /v1/oauth/token` ein `200` mit einem `access_token`, das mit `sk-ant-oat01-` beginnt, und einem `expires_in`-Wert in Sekunden zurückgibt. Wenn der Austausch mit der undurchsichtigen `401`-`authentication_error`-Antwort (Meldung `Authentication failed`) fehlschlägt, prüfe auf der [Seite mit dem Authentifizierungsverlauf](https://platform.claude.com/settings/workload-identity-federation?tab=history) in der Claude Console den Ablehnungsgrund, dekodiere dann das von Entra ausgestellte Token aus Schritt 1 (den Befehl findest du unter [Fehlerbehebung bei einem fehlgeschlagenen Austausch](https://platform.claude.com/docs/de/manage-claude/wif-reference#troubleshoot-a-failed-exchange)) und prüfe die häufigsten Ursachen auf Azure-Seite:

* **Issuer-Abweichung:** Die registrierte `issuer_url` muss exakt mit dem `iss`-Claim des Tokens übereinstimmen. Ein v2.0-Token trägt `https://login.microsoftonline.com/<TENANT_ID>/v2.0`; wenn der dekodierte `ver`-Claim `1.0` ist, siehe [Wenn deine Token v1.0 sind](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).
* **Token-Lebensdauer:** Wenn eine Token-Lebensdauer-Richtlinie des Mandanten oder CAE das `client_credentials`-Token über 7500 Sekunden hinaus verlängert, erhöhe `max_jwt_lifetime_seconds` des Issuers, wie in [Anthropic konfigurieren](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#configure-anthropic-2) beschrieben.
* **Audience-Abweichung:** Die `audience` der Regel muss exakt dem `aud` des Tokens entsprechen: der Client-ID der Audience-App-Registrierung für die v2.0-Token, die dieser Leitfaden konfiguriert.
* **Claim-Namen-Abweichung:** Eine Regel, die auf einen Claim abgleicht, den das Token nicht trägt, besteht nie. v1.0-Token tragen die Client-ID in `appid`, nicht in `azp`; siehe [Wenn deine Token v1.0 sind](https://platform.claude.com/docs/de/manage-claude/wif-providers/azure#if-your-tokens-are-v1-0).

## Wenn deine Token v1.0 sind

Dieser Leitfaden konfiguriert die Audience-App-Registrierung mit `api.requestedAccessTokenVersion: 2`, sodass jedes gezeigte Token v2.0 ist. Wenn du eine bestehende Registrierung wiederverwendest, die `requestedAccessTokenVersion` ungesetzt lässt, stellt Entra stattdessen v1.0-Token aus. Dekodiere ein Beispiel-Token und prüfe seinen `ver`-Claim; wenn er `1.0` ist, ändern sich vier Dinge:

* **Issuer:** Der `iss`-Claim ist `https://sts.windows.net/<TENANT_ID>/` statt `https://login.microsoftonline.com/<TENANT_ID>/v2.0`. Registriere die Issuer-URL exakt so, wie der `iss`-Claim deines Tokens sie trägt. Die beiden URLs teilen sich dasselbe JWKS, sodass der Discovery-Modus für beide funktioniert.
* **Auswahl im Assistenten:** Wähle **v1 (sts.windows.net)** in der Auswahl **Token issuer** des Assistenten „Connect workload“ statt **v2.0 (login.microsoftonline.com)**.
* **Audience:** Der `aud`-Claim ist die Bezeichner-URI, die du als `resource` übergeben hast (zum Beispiel `api://<APP_ID>`), nicht die Client-ID der Registrierung. Setze die `audience` der Föderationsregel auf den exakten `aud`-Wert aus deinem dekodierten Token.
* **Client-ID-Claim:** Die Client-ID der aufrufenden Identität erscheint in `appid`, nicht in `azp`. Die beiden Claims erscheinen nie im selben Token, sodass eine Regel, die auf `azp` abgleicht, gegen ein v1.0-Token nie besteht.

Die Claims `oid`, `sub` und `tid` tragen in beiden Versionen dieselben Werte, sodass der Rest dieses Leitfadens unverändert gilt.

## Deine Regel eingrenzen

Eine Föderationsregel kann das Subject des Tokens zusätzlich zur (oder anstelle der) `claims`-Map mit `subject_prefix` abgleichen; siehe [Semantik des Regelabgleichs](https://platform.claude.com/docs/de/manage-claude/wif-reference#rule-matching-semantics) dazu, wie die Felder kombiniert werden. Entra-`sub`-Werte für diese Identitäten sind kanonische GUIDs fester Länge, sodass ein `subject_prefix`, das die vollständige 36-stellige Objekt-ID enthält, nur auf dieses Subject passt; dies ist eine Eigenschaft von Entras Subject-Format, nicht von `subject_prefix` im Allgemeinen.

<Warning>
  Jede Identität in deinem Mandanten kann ein Token für die registrierte Audience anfordern, sodass `audience` und `tid` allein keinen bestimmten Workload identifizieren. Eine Regel, die einen `oid`-Abgleich (oder `azp`/`appid`) auslässt oder die ein Wildcard- oder Teil-GUID-`subject_prefix` verwendet, autorisiert jede verwaltete Identität und jeden Dienstprinzipal im Mandanten.
</Warning>

Beschränke den `match`-Block der Regel auf den engsten Geltungsbereich, der zu deinem Anwendungsfall passt:

* **`oid` als exakten Wert abgleichen:** Setze `claims.oid` auf die vollständige Objekt-ID der verwalteten Identität. Ein auf diese vollständige Objekt-ID gesetztes `subject_prefix` ist äquivalent (der Console-Assistent setzt beides); verwende niemals ein Wildcard- oder Teil-GUID-`subject_prefix`, das auf mehr Identitäten passt, als du beabsichtigst.
* **`tid` als Defense in Depth festlegen:** Die Issuer-URL legt deinen Mandanten bereits fest, aber das Hinzufügen von `claims.tid` schützt vor Konfigurationsdrift, falls der Issuer-Eintrag später bearbeitet wird.
* **Die Audience festlegen:** Setze `audience` auf den exakten `aud`-Wert aus deinem dekodierten Token, damit für andere Anwendungen ausgestellte Token abgelehnt werden.
* **Eine separate Regel für jede verwaltete Identität verwenden:** Erstelle eine Regel für jede Identität statt einer Regel, die mehrere autorisiert, damit du den Zugriff eines einzelnen Workloads widerrufen kannst, ohne andere zu beeinträchtigen.

## Nächste Schritte

* Sieh dir das vollständige Konfigurationsmodell in [Workload Identity Federation](https://platform.claude.com/docs/de/manage-claude/workload-identity-federation) an.
* Siehe die [Anbieter-Leitfäden](https://platform.claude.com/docs/de/manage-claude/workload-identity-federation#identity-providers) für AWS, Google Cloud, GitHub Actions und Kubernetes.
* Zu Umgebungsvariablen, Profildateien und der Rangfolge von Anmeldeinformationen siehe die [WIF-Referenz](https://platform.claude.com/docs/de/manage-claude/wif-reference).
