---
title: 搭配 Okta 使用 WIF
url: https://platform.claude.com/docs/zh-TW/manage-claude/wif-providers/okta
description: 透過 Workload Identity Federation 將 Okta 服務應用程式身分聯合至 Claude API。
---

Okta 可以透過 OAuth 2.0 `client_credentials` 授權類型向**服務應用程式**（service application）核發 OIDC 存取權杖，藉此充當工作負載身分提供者。您的工作負載向 Okta 進行驗證（通常使用 `private_key_jwt`，因此不會儲存共用密鑰），取得一個已簽署的「JSON Web Token」（JSON 網頁權杖），即 JWT，然後將該 JWT 與 Anthropic 交換以取得短期存取權杖。

Okta 授權伺服器的簽發者 URL 格式為 `https://<your-domain>.okta.com/oauth2/<auth-server-id>`。如果您使用內建的預設伺服器，路徑為 `/oauth2/default`。

<Note>
  您必須使用 Okta **自訂授權伺服器**（custom authorization server，包括 `default` 伺服器）。由 Okta 組織授權伺服器直接核發的權杖（路徑中不含授權伺服器 ID 的 `/oauth2/v1/token` 端點）無法由外部方驗證，因為 Okta 不會為其發布簽署金鑰。
</Note>

設定 Okta 及向其進行驗證的方式有很多種，這些超出本文件的範圍。請確保您的設定與驗證機制遵循貴公司的指引與安全實務。

## 先決條件

* 熟悉 [WIF 概念](https://platform.claude.com/docs/zh-TW/manage-claude/workload-identity-federation#concepts)：服務帳戶、聯合簽發者與聯合規則。
* 已啟用 API Access Management 的 Okta 組織（自訂授權伺服器所必需）。
* 在 Claude Console 中為您的 Anthropic 組織建立服務帳戶、聯合簽發者與聯合規則的權限。
* 一個能夠向 Okta 的 `/v1/token` 端點請求權杖並可連線至 `api.anthropic.com` 的工作負載。

## 設定 Okta

概略而言，您需要：

1. 建立一個 Okta 服務應用程式。
2. 為您的預設授權伺服器（或建立新的自訂授權伺服器）設定受眾（audience）、範圍（scope）、存取原則，以及您想要比對的任何自訂宣告（claims）。

確切的導覽路徑取決於您的 Okta 組織設定與管理主控台版本。以下編號步驟說明一種常見的路徑：

1. **建立服務應用程式整合。** 在 Okta Admin Console 中，建立一個類型為 **API Services**（OIDC，機器對機器）的新應用程式整合。記下產生的 **Client ID**。
2. **設定用戶端驗證。** 若要採用無金鑰設定，請選擇 **Public key / Private key**（`private_key_jwt`）並註冊您工作負載的公開 JWK。或者，如果您的環境能夠安全地儲存用戶端密鑰，也可以使用用戶端密鑰。對於以下範例，您可能需要停用應用程式上的 DPoP 要求；請確保您的正式環境設定符合貴組織的安全要求。
3. **設定受眾。** 在您的自訂授權伺服器上，將受眾設為 `https://api.anthropic.com`，使核發的存取權杖帶有該 `aud` 宣告。Anthropic 會依此固定值驗證 `aud`。
4. **授予範圍。** 在您的自訂授權伺服器上，確保至少存在一個服務應用程式被允許請求的範圍（例如 `anthropic.access`）。Okta 會拒絕未包含已授予範圍的 `client_credentials` 請求。
5. **建立存取原則。** 在您的自訂授權伺服器上，建立一個存取原則，其中至少包含一條規則，允許您的服務應用程式請求您在步驟 4 中授予的範圍。
6. **（選用）新增自訂宣告。** 如果您想比對用戶端 ID 以外的內容，請在授權伺服器的 **Claims** 分頁中為存取權杖新增宣告。

對於使用 `client_credentials` 的服務應用程式，Okta 會將核發之存取權杖的 `sub` 宣告設為應用程式的 **Client ID**，並將 `iss` 設為授權伺服器的簽發者 URL。

## 設定 Anthropic

在 Claude Console 中，前往 [Workload identity](https://platform.claude.com/settings/workload-identity-federation) 頁面（`platform.claude.com/settings/workload-identity-federation`），點擊 **Connect workload**，然後選擇 **Custom OIDC**。精靈會引導您完成註冊簽發者、建立服務帳戶和建立聯合規則的步驟。

精靈會為您建立這些資源。無論您是在精靈中輸入這些值，還是將它們傳送至 [Admin API](https://platform.claude.com/docs/zh-TW/manage-claude/wif-admin-api)，請使用下列值：

**聯合簽發者：** 使用您的 Okta 自訂授權伺服器 URL 與探索模式。Anthropic 會讀取 Okta 的 `.well-known/openid-configuration` 探索文件，並從其公告的 `jwks_uri` 擷取 JWKS。

```json
{
  "name": "okta-prod",
  "issuer_url": "https://acme.okta.com/oauth2/aus1a2b3c4d5e6f7g8h9",
  "jwks": { "type": "discovery" }
}
```

**聯合規則：** 比對 Okta 的 `sub` 宣告，即服務應用程式的 Client ID。如果您在 Okta 中定義了自訂宣告，則可以改用 `claims` 對應或 CEL `condition` 來比對這些宣告。

```json
{
  "name": "okta-pipeline",
  "issuer_id": "fdis_...",
  "match": {
    "subject_prefix": "0oa1b2c3d4e5f6g7h8i9",
    "audience": "https://api.anthropic.com"
  },
  "target": { "type": "service_account", "service_account_id": "svac_..." },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}
```

## 取得權杖並呼叫 Claude API

與平台原生提供者（AWS、Google Cloud、Kubernetes）不同，這些提供者會在工作負載的執行環境中提供權杖（透過投射檔案或本機中繼資料端點），而 Okta 不會。您的工作負載必須呼叫 Okta 的權杖端點以取得 JWT，然後將該 JWT 作為身分權杖傳遞給 Anthropic SDK。

<CodeGroup>
  ```bash cURL
  # 1. 向 Okta 請求存取權杖（使用 private_key_jwt 的 client_credentials）。
  OKTA_JWT=$(curl -sS "https://acme.okta.com/oauth2/aus1a2b3c4d5e6f7g8h9/v1/token" \
    -d grant_type=client_credentials \
    -d scope=anthropic.access \
    -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
    --data-urlencode client_assertion="$SIGNED_CLIENT_ASSERTION" \
    | jq -r .access_token)

  # 2. 將 Okta JWT 交換為 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": "$OKTA_JWT",
    "federation_rule_id": "$ANTHROPIC_FEDERATION_RULE_ID",
    "organization_id": "$ANTHROPIC_ORGANIZATION_ID",
    "service_account_id": "$ANTHROPIC_SERVICE_ACCOUNT_ID",
    "workspace_id": "$ANTHROPIC_WORKSPACE_ID"
  }
  JSON
  )

  # 3. 呼叫 Claude API。
  curl https://api.anthropic.com/v1/messages \
    -H "authorization: Bearer $ACCESS_TOKEN" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{"model": "claude-opus-5-5", "max_tokens": 1024, "messages": [{"role": "user", "content": "Hello, Claude"}]}' \
    | jq -r '.content[] | select(.type == "text") | .text'
  ```

  ```python Python
  import os
  import httpx2
  import anthropic
  from anthropic import WorkloadIdentityCredentials


  def fetch_okta_token() -> str:
      response = httpx2.post(
          f"{os.environ['OKTA_ISSUER']}/v1/token",
          data={
              "grant_type": "client_credentials",
              "scope": "anthropic.access",
              "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
              # 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
              "client_assertion": build_signed_client_assertion(),
          },
      )
      response.raise_for_status()
      return response.json()["access_token"]


  client = anthropic.Anthropic(
      credentials=WorkloadIdentityCredentials(
          identity_token_provider=fetch_okta_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, Claude"}],
  )
  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";

  async function fetchOktaToken(): Promise<string> {
    const response = await fetch(`${process.env.OKTA_ISSUER}/v1/token`, {
      method: "POST",
      headers: { "content-type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        grant_type: "client_credentials",
        scope: "anthropic.access",
        client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
        // 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
        client_assertion: buildSignedClientAssertion()
      })
    });
    const body = (await response.json()) as { access_token: string };
    return body.access_token;
  }

  const client = new Anthropic({
    credentials: oidcFederationProvider({
      identityTokenProvider: fetchOktaToken,
      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, Claude" }]
  });
  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 fetchOktaToken(ctx context.Context) (string, error) {
  	form := url.Values{
  		"grant_type":            {"client_credentials"},
  		"scope":                 {"anthropic.access"},
  		"client_assertion_type": {"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
  		// 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
  		"client_assertion": {buildSignedClientAssertion()},
  	}
  	req, err := http.NewRequestWithContext(ctx, http.MethodPost,
  		os.Getenv("OKTA_ISSUER")+"/v1/token", 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(fetchOktaToken), 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, Claude")),
  		},
  	})
  	if err != nil {
  		panic(err)
  	}
  	for _, block := range message.Content {
  		if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  			fmt.Println(textBlock.Text)
  			break
  		}
  	}
  }
  ```

  ```java Java
  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.util.Map;
  import java.util.stream.Collectors;
  import static java.nio.charset.StandardCharsets.UTF_8;

  void main() throws Exception {
      var form = Map.of(
                      "grant_type", "client_credentials",
                      "scope", "anthropic.access",
                      "client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
                      // 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
                      "client_assertion", buildSignedClientAssertion())
              .entrySet().stream()
              .map(entry -> entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), UTF_8))
              .collect(Collectors.joining("&"));
      var request = HttpRequest.newBuilder(URI.create(System.getenv("OKTA_ISSUER") + "/v1/token"))
              .header("content-type", "application/x-www-form-urlencoded")
              .POST(HttpRequest.BodyPublishers.ofString(form))
              .build();

      // Java SDK 接受權杖本身或檔案路徑，而非函式；使用
      // source("value") 時，path(...) 存放權杖。SDK 會在每次重新整理
      // Anthropic 存取權杖時傳送同一個權杖，一旦該權杖
      // 過期，或（若含 jti 宣告）已被使用過，就會失敗。對於長時間執行的
      // 程序，請傳入 source("file")，並在每次重新整理前
      // 將新權杖寫入該檔案。
      var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
      String oktaToken = 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(oktaToken)
                                      .build())
                              .build())
                      .build()))
              .build();

      var message = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024)
              .addUserMessage("Hello, Claude")
              .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 OktaTokenProvider(),
  });
  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, Claude" }],
  });
  foreach (var block in message.Content)
  {
      if (block.Value is TextBlock textBlock)
      {
          Console.WriteLine(textBlock.Text);
      }
  }

  class OktaTokenProvider : IIdentityTokenProvider
  {
      private static readonly HttpClient Http = new();

      public async Task<string> GetIdentityTokenAsync(CancellationToken ct = default)
      {
          var form = new FormUrlEncodedContent(new Dictionary<string, string>
          {
              ["grant_type"] = "client_credentials",
              ["scope"] = "anthropic.access",
              ["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
              // 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
              ["client_assertion"] = BuildSignedClientAssertion(),
          });
          var response = await Http.PostAsync(
              $"{Environment.GetEnvironmentVariable("OKTA_ISSUER")}/v1/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()!;
      }
  }
  ```

  ```bash CLI
  # 1. 向 Okta 請求存取權杖，並將其寫入暫存檔案。
  ANTHROPIC_IDENTITY_TOKEN_FILE=$(mktemp)
  curl -sS "$OKTA_ISSUER/v1/token" \
    -d grant_type=client_credentials \
    -d scope=anthropic.access \
    -d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
    --data-urlencode client_assertion="$SIGNED_CLIENT_ASSERTION" \
    | jq -r .access_token > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
  export ANTHROPIC_IDENTITY_TOKEN_FILE

  # 2. 呼叫 Claude API。CLI 會讀取 ANTHROPIC_FEDERATION_RULE_ID、
  # ANTHROPIC_ORGANIZATION_ID、ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID 及
  # ANTHROPIC_IDENTITY_TOKEN_FILE，並執行交換。
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello, Claude"}'
  ```

  ```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 OktaIdentityToken implements IdentityTokenProvider
  {
      public function getIdentityToken(): string
      {
          $ch = curl_init(getenv('OKTA_ISSUER') . '/v1/token');
          curl_setopt_array($ch, [
              CURLOPT_RETURNTRANSFER => true,
              CURLOPT_POSTFIELDS => http_build_query([
                  'grant_type' => 'client_credentials',
                  'scope' => 'anthropic.access',
                  'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
                  // 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
                  'client_assertion' => buildSignedClientAssertion(),
              ]),
          ]);
          $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 OktaIdentityToken(),
              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, Claude']],
  );
  echo array_find($message->content, static fn ($block): bool => $block->type === 'text')->text, PHP_EOL;
  ```

  ```ruby Ruby
  require "anthropic"
  require "json"
  require "net/http"

  def fetch_okta_token
    uri = URI("#{ENV.fetch('OKTA_ISSUER')}/v1/token")
    response = Net::HTTP.post_form(
      uri,
      "grant_type" => "client_credentials",
      "scope" => "anthropic.access",
      "client_assertion_type" => "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
      # 建立 RFC 7523 client_assertion JWT，並以您 Okta 應用程式的私密金鑰簽署
      "client_assertion" => build_signed_client_assertion
    )
    JSON.parse(response.body).fetch("access_token")
  end

  client = Anthropic::Client.new(
    credentials: Anthropic::WorkloadIdentityCredentials.new(
      identity_token_provider: -> { fetch_okta_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"]
    )
  )

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

除了 Java 之外（請參閱該範例中的註解），SDK 範例會將您的 Okta 權杖擷取函式作為權杖提供者傳遞給 `identity_token_provider` (typescript: `identityTokenProvider`; php: `identityProvider`; csharp: `IdentityTokenProvider`; go: `option.WithFederationTokenProvider`; java: `IdentityTokenConfig`)。每當 Anthropic 存取權杖即將到期時，Claude SDK 就會呼叫它，因此您的 Okta 擷取函式應在每次呼叫時傳回新的權杖，而不是無限期地快取同一個權杖。`ant` CLI 會在每次交換時重新讀取 `ANTHROPIC_IDENTITY_TOKEN_FILE`，因此對於長時間執行的 shell，請以計時器定期更新該檔案。

## 驗證設定

成功的交換會傳回以 `sk-ant-oat01-` 開頭的 `access_token`，以及以秒為單位的 `expires_in` 值。如果交換失敗並傳回不透明的 `401` `authentication_error` 回應（訊息為 `Authentication failed`），請查看 Claude Console 中的[驗證歷史記錄頁面](https://platform.claude.com/settings/workload-identity-federation?tab=history)以了解拒絕原因，並參閱[疑難排解失敗的交換](https://platform.claude.com/docs/zh-TW/manage-claude/wif-reference#troubleshoot-a-failed-exchange)；Okta 端最常見的原因是 `issuer_url` 不符（它必須包含 `/oauth2/<auth-server-id>` 路徑；Okta 組織授權伺服器無法使用）。

## 限定規則範圍

<Warning>
  同一個 Okta 授權伺服器下的多個服務應用程式共用相同的 簽發者。省略 `subject_prefix` 的規則會比對該伺服器上的每一個服務應用程式， 因此任何能夠註冊服務應用程式的團隊都可能取得聯合的 Anthropic 權杖。
</Warning>

將規則的 `match` 區塊鎖定在符合您使用情境的最小範圍：

* **固定確切的 Client ID：** 將 `subject_prefix` 設為服務應用程式的完整 Client ID，結尾不加 `*`。
* **固定受眾：** 比對您在授權伺服器上設定的 `audience` 值，使為其他受眾鑄造的權杖遭到拒絕。
* **比對自訂宣告：** 若需更細緻的範圍限定，請在授權伺服器的 **Claims** 分頁中新增宣告，並以規則的 `claims` 對應或 CEL `condition` 進行比對。
* **每個服務應用程式使用一條規則：** 為每個服務應用程式建立個別的聯合規則，而非在多個應用程式之間共用一條規則。

## 後續步驟

* 檢閱 [WIF 參考文件](https://platform.claude.com/docs/zh-TW/manage-claude/wif-reference)以了解完整的憑證解析順序與設定檔設定。
* 參閱 [WIF 參考文件](https://platform.claude.com/docs/zh-TW/manage-claude/wif-reference#rule-matching-semantics)以使用 CEL 運算式比對自訂 Okta 宣告。
