---
title: GitHub ActionsでWIFを使用する
url: https://platform.claude.com/docs/ja/manage-claude/wif-providers/github-actions
description: 長期間有効なAPIキーの代わりに、短期間有効なIDトークンを使用してGitHub ActionsワークフローをClaude APIに対して認証します。
---

すべてのGitHub Actionsワークフロー実行は、`https://token.actions.githubusercontent.com` にあるGitHubのホスト型発行者から、署名付きのIDトークンをリクエストできます。「Workload Identity Federation」（ワークロードIDフェデレーション）を使用すると、ワークフローはそのトークンを短期間有効なAnthropicアクセストークンと交換します。そのため、CIジョブはリポジトリに `ANTHROPIC_API_KEY` シークレットを保存しなくてもClaude APIを呼び出せます。

トークンの `sub` クレームには、リポジトリとトリガーのコンテキストがエンコードされています。ブランチへのプッシュの場合、形式は `repo:<owner>/<repo>:ref:refs/heads/<branch>` です。プルリクエストの実行では `repo:<owner>/<repo>:pull_request` が使用されます。環境で保護されたデプロイでは `repo:<owner>/<repo>:environment:<name>` が使用されます。フェデレーションルールは、このクレーム（および `repository_owner` や `ref` などの他のクレーム）と照合して、どのワークフロー実行に認証を許可するかを決定します。

## 前提条件

* [WIFの概念](https://platform.claude.com/docs/ja/manage-claude/workload-identity-federation#concepts)（サービスアカウント、フェデレーション発行者、フェデレーションルール）を理解していること。
* ワークフローファイルを編集でき、`id-token: write` 権限を付与できるGitHubリポジトリ。
* Anthropicの組織に対して、Claude Consoleでサービスアカウント、フェデレーション発行者、フェデレーションルールを作成する権限。
* Anthropic組織ID。Claude Consoleの[Organization](https://platform.claude.com/settings/organization)ページ（`platform.claude.com/settings/organization`）で確認できます。

## ワークフローを設定する

GitHubは、明示的に要求したジョブにのみIDトークンを発行します。ワークフローレベルまたはジョブレベルで `id-token: write` 権限を追加します。

```yaml
permissions:
  id-token: write
  contents: read
```

ジョブ内では、ランナーが `ACTIONS_ID_TOKEN_REQUEST_URL` と `ACTIONS_ID_TOKEN_REQUEST_TOKEN` という2つの環境変数を公開します。リクエストトークンをベアラー認証情報として、選択したオーディエンスをクエリパラメータとして指定してリクエストURLを呼び出し、返された「JSON Web Token」（JSONウェブトークン）、すなわちJWTをファイルに書き込みます。

```yaml
- name: Fetch GitHub OIDC token
  run: |
    curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
      "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \
      | jq -r .value > /tmp/gha-jwt
```

JavaScriptを使用したい場合は、`actions/github-script` が `core.getIDToken(audience)` を通じて同じ機能を公開しています。

```yaml
- name: Fetch GitHub OIDC token
  uses: actions/github-script@v8
  with:
    script: |
      const fs = require('fs');
      const token = await core.getIDToken('https://api.anthropic.com');
      fs.writeFileSync('/tmp/gha-jwt', token);
```

デコードされたトークンには、ワークフロー実行を記述するクレームが含まれています。フェデレーションルールはこれらと照合します。

```json
{
  "iss": "https://token.actions.githubusercontent.com",
  "sub": "repo:your-org/your-repo:ref:refs/heads/main",
  "aud": "https://api.anthropic.com",
  "repository": "your-org/your-repo",
  "repository_owner": "your-org",
  "ref": "refs/heads/main",
  "sha": "abc123...",
  "workflow": "CI",
  "actor": "octocat",
  "event_name": "push"
}
```

`sub` 形式の完全な一覧については、[GitHubのOIDCサブジェクトクレームリファレンス](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#example-subject-claims)を参照してください。

## Anthropicを設定する

Claude Consoleで[Workload identity](https://platform.claude.com/settings/workload-identity-federation)ページ（`platform.claude.com/settings/workload-identity-federation`）に移動し、**Connect workload**をクリックして、**GitHub Actions**タイルを選択します。ウィザードに従って、発行者の登録、サービスアカウントの作成、フェデレーションルールの作成を行います。

ウィザードがこれらのリソースを作成します。ウィザードに入力する場合でも、[Admin API](https://platform.claude.com/docs/ja/manage-claude/wif-admin-api)に送信する場合でも、以下の値を使用してください。

**フェデレーション発行者：** GitHubはOIDCディスカバリードキュメントとJWKSを公開しているため、ディスカバリーモードを使用します。GitHubが鍵をローテーションすると、Anthropicは自動的に鍵を更新します。

```json
{
  "name": "github-actions",
  "issuer_url": "https://token.actions.githubusercontent.com",
  "jwks": { "type": "discovery" }
}
```

**フェデレーションルール：** 信頼する予定のワークフロー実行のみに一致させます。これらのクレームを安全にスコープ設定する方法については、[認証できるワークフローを制限する](https://platform.claude.com/docs/ja/manage-claude/wif-providers/github-actions#restrict-which-workflows-can-authenticate)を参照してください。

```json
{
  "name": "gha-main",
  "issuer_id": "fdis_...",
  "match": {
    "subject_prefix": "repo:your-org/your-repo:ref:refs/heads/main",
    "audience": "https://api.anthropic.com",
    "claims": {
      "repository_owner": "your-org"
    }
  },
  "target": {
    "type": "service_account",
    "service_account_id": "svac_..."
  },
  "workspace_id": "wrkspc_...",
  "oauth_scope": "workspace:developer",
  "token_lifetime_seconds": 600
}
```

ワークロードが許す限り具体的に指定してください。`sub` の末尾セグメントは `ref:...`、`environment:...`、`pull_request` の各イベント間で異なるため、同じリポジトリからの複数のイベントタイプにルールを一致させる必要がある場合にのみ、`subject_prefix` を `repo:your-org/your-repo:*` に緩めてください（`claims.ref` 制約と組み合わせて使用します）。

## トークンを取得して使用する

ジョブにフェデレーション用の環境変数を設定し、通常どおりSDKを呼び出します。`Anthropic()` (typescript: `new Anthropic()`; csharp: `new AnthropicClient()`; go: `anthropic.NewClient()`; java: `AnthropicOkHttpClient.fromEnv()`; php: `new Client()`; ruby: `Anthropic::Client.new`) は `ANTHROPIC_IDENTITY_TOKEN_FILE` を読み取り、最初のリクエスト時にJWTを交換します。また、アクセストークンの有効期限が切れる前に自動的に更新します。

<CodeGroup>
  ```yaml Workflow
  name: Call Claude
  on: push

  permissions:
    id-token: write
    contents: read

  jobs:
    call-claude:
      runs-on: ubuntu-latest
      env:
        ANTHROPIC_FEDERATION_RULE_ID: fdrl_...
        ANTHROPIC_ORGANIZATION_ID: 00000000-0000-0000-0000-000000000000
        ANTHROPIC_SERVICE_ACCOUNT_ID: svac_...
        ANTHROPIC_WORKSPACE_ID: wrkspc_...  # required when the rule covers multiple workspaces
        ANTHROPIC_IDENTITY_TOKEN_FILE: /tmp/gha-jwt
      steps:
        - uses: actions/checkout@v5
        - name: Fetch GitHub OIDC token
          run: |
            curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
              "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \
              | jq -r .value > "$ANTHROPIC_IDENTITY_TOKEN_FILE"
        - name: Run your script
          run: |
            pip install anthropic
            python your_script.py
  ```

  ```bash cURL
  JWT=$(cat /tmp/gha-jwt)

  RESPONSE=$(curl -sS https://api.anthropic.com/v1/oauth/token \
    -H "content-type: application/json" \
    --data @- <<JSON
  {
    "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "assertion": "$JWT",
    "federation_rule_id": "$ANTHROPIC_FEDERATION_RULE_ID",
    "organization_id": "$ANTHROPIC_ORGANIZATION_ID",
    "service_account_id": "$ANTHROPIC_SERVICE_ACCOUNT_ID",
    "workspace_id": "$ANTHROPIC_WORKSPACE_ID"
  }
  JSON
  )

  ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r .access_token)

  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 anthropic

  # ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  # ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID、ANTHROPIC_IDENTITY_TOKEN_FILE を
  # ジョブ環境から読み取ります。
  client = anthropic.Anthropic()

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

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

  // ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  // ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID、ANTHROPIC_IDENTITY_TOKEN_FILE を
  // ジョブ環境から読み取ります。
  const client = new Anthropic();

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

  ```go Go
  // ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  // ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID、ANTHROPIC_IDENTITY_TOKEN_FILE を
  // ジョブ環境から読み取ります。
  client := anthropic.NewClient()

  message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Hello, Claude")),
  	},
  })
  if err != nil {
  	panic(err)
  }
  for _, block := range message.Content {
  	if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
  		fmt.Println(textBlock.Text)
  		break
  	}
  }
  ```

  ```java Java
  AnthropicClient client = AnthropicOkHttpClient.fromEnv();

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

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

  ```csharp C#
  // ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  // ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID、ANTHROPIC_IDENTITY_TOKEN_FILE を
  // ジョブ環境から読み取ります。
  using var client = new AnthropicClient();

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

  ```bash 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;

  // ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  // ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID、ANTHROPIC_IDENTITY_TOKEN_FILE を
  // ジョブ環境から読み取ります。
  $client = new Client();

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

  ```ruby Ruby
  require "anthropic"

  # ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
  # ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID、ANTHROPIC_IDENTITY_TOKEN_FILE を
  # ジョブ環境から読み取ります。
  client = Anthropic::Client.new

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

GitHubが発行する各IDトークンは、発行から約5分で有効期限が切れます。一方、トークンリクエストエンドポイント（`ACTIONS_ID_TOKEN_REQUEST_URL`）はジョブの実行中ずっと有効なため、いつでも新しいトークンを取得できます。SDKは最初の使用時にトークンを交換し、取得したAnthropicアクセストークンをキャッシュします。Anthropicトークンの有効期間より長く実行されるジョブでは、SDKが更新のたびに `ANTHROPIC_IDENTITY_TOKEN_FILE` を再読み込みします。そのため、取得ステップを定期的に再実行して（またはバックグラウンドループで実行して）、ファイルを最新の状態に保ってください。別の方法として、Javaを除き、ファイルパスを使用する代わりに、`ACTIONS_ID_TOKEN_REQUEST_URL` を直接呼び出すトークンプロバイダーをSDKに渡すこともできます。

## セットアップを検証する

交換が成功すると、`sk-ant-oat01-`で始まる`access_token`と、秒単位の`expires_in`値が返されます。交換が拒否されると、どのチェックが失敗したかにかかわらず、固定メッセージ`Authentication failed`を含む不透明な`401` `authentication_error`が返されます。ほとんどの場合、拒否理由はClaude Consoleの[認証履歴ページ](https://platform.claude.com/settings/workload-identity-federation?tab=history)にある該当試行のエントリに記録されます。また、[失敗した交換のトラブルシューティング](https://platform.claude.com/docs/ja/manage-claude/wif-reference#troubleshoot-a-failed-exchange)では、チェックを順番に確認する方法を説明しています。GitHub Actions側で最も一般的な原因は、`sub`クレームの形式が一致しないことです（その末尾のセグメントは`ref:...`、`environment:...`、`pull_request`イベントの間で異なります）。この場合、履歴エントリには理由`match_subject_prefix`が表示されます。

## 認証できるワークフローを制限する

<Warning>
  `subject_prefix` に `repo:your-org/*` のみを指定すると、組織内のすべてのリポジトリに一致し、`ref` 制約がない場合はフォークからトリガーされた `pull_request` 実行にも一致します。一致するリポジトリに対してプルリクエストを開くことができる人なら誰でも、フェデレーションされたAnthropicトークンを取得できる可能性があります。
</Warning>

ルールの `match` ブロックを、ユースケースに適合する最も狭いスコープに固定してください。

* **単一のリポジトリに固定する：** `subject_prefix: "repo:your-org/your-repo:*"` を使用して、組織内の他のリポジトリが一致しないようにします。
* **保護されたブランチに固定する：** `claims` の下に `"ref": "refs/heads/main"`（またはリリースブランチ）を追加して、プルリクエスト実行やフィーチャーブランチが一致しないようにします。
* **オーナーを明示的に固定する：** `sub` の解析におけるエッジケースに対する多層防御のチェックとして、`claims` の下に `"repository_owner": "your-org"` を追加します。
* **デプロイメント環境に固定する：** デプロイジョブの場合、`subject_prefix: "repo:your-org/your-repo:environment:production"` に一致させ、GitHubで必須レビュアーを設定してその環境をゲートします。

## 次のステップ

* [Workload Identity Federation](https://platform.claude.com/docs/ja/manage-claude/workload-identity-federation)：完全なセットアップ手順、環境変数、認証情報の優先順位。
* [認証](https://platform.claude.com/docs/ja/manage-claude/authentication)：フェデレーションとAPIキーの比較。
