---
title: Usar WIF com GitHub Actions
url: https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/github-actions
description: Autentique workflows do GitHub Actions na Claude API com tokens de identidade de curta duração em vez de chaves de API de longa duração.
---

Cada execução de workflow do GitHub Actions pode solicitar um token de identidade assinado do emissor hospedado do GitHub em `https://token.actions.githubusercontent.com`. Com "Workload Identity Federation" (federação de identidade de carga de trabalho), ou WIF, seu workflow troca esse token por um token de acesso da Anthropic de curta duração, para que seus jobs de CI possam chamar a Claude API sem um segredo `ANTHROPIC_API_KEY` armazenado no seu repositório.

A claim `sub` do token codifica o repositório e o contexto do gatilho. Para um push em uma branch, ela tem a forma `repo:<owner>/<repo>:ref:refs/heads/<branch>`. Execuções de pull request usam `repo:<owner>/<repo>:pull_request`, e implantações controladas por ambiente usam `repo:<owner>/<repo>:environment:<name>`. Sua regra de federação faz a correspondência com essa claim (e outras, como `repository_owner` e `ref`) para decidir quais execuções de workflow têm permissão para se autenticar.

## Pré-requisitos

* Familiaridade com os [conceitos de WIF](https://platform.claude.com/docs/pt-BR/manage-claude/workload-identity-federation#concepts): contas de serviço, emissores de federação e regras de federação.
* Um repositório GitHub onde você possa editar arquivos de workflow e conceder a permissão `id-token: write`.
* Permissão para criar contas de serviço, emissores de federação e regras de federação no Claude Console para sua organização Anthropic.
* O ID da sua organização da Anthropic. Você pode encontrá-lo na página [Organization](https://platform.claude.com/settings/organization) (`platform.claude.com/settings/organization`) no Claude Console.

## Configure seu workflow

O GitHub só emite um token de identidade para jobs que o solicitam explicitamente. Adicione a permissão `id-token: write` no nível do workflow ou do job:

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

Dentro do job, o runner expõe duas variáveis de ambiente: `ACTIONS_ID_TOKEN_REQUEST_URL` e `ACTIONS_ID_TOKEN_REQUEST_TOKEN`. Chame a URL de solicitação com o token de solicitação como credencial bearer e o audience escolhido como parâmetro de consulta, e então grave o "JSON Web Token" (token web JSON), ou JWT, retornado em um arquivo:

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

Se você preferir JavaScript, `actions/github-script` expõe a mesma capacidade por meio de `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);
```

O token decodificado carrega claims que descrevem a execução do workflow. Sua regra de federação faz a correspondência com elas:

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

Consulte a [referência de claims de subject OIDC do GitHub](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#example-subject-claims) para a lista completa de formatos de `sub`.

## Configure a Anthropic

No Claude Console, acesse a página [Workload identity](https://platform.claude.com/settings/workload-identity-federation) (`platform.claude.com/settings/workload-identity-federation`), clique em **Connect workload** e selecione o bloco **GitHub Actions**. O assistente orienta você no registro do emissor, na criação de uma conta de serviço e na criação de uma regra de federação.

O assistente cria esses recursos para você. Use os seguintes valores, seja inserindo-os no assistente ou enviando-os para a [Admin API](https://platform.claude.com/docs/pt-BR/manage-claude/wif-admin-api):

**Emissor de federação:** O GitHub publica seu documento de descoberta OIDC e seu JWKS publicamente, portanto use o modo de descoberta. A Anthropic atualiza as chaves automaticamente quando o GitHub as rotaciona.

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

**Regra de federação:** Faça a correspondência apenas com as execuções de workflow em que você pretende confiar. Consulte [Restrinja quais workflows podem se autenticar](https://platform.claude.com/docs/pt-BR/manage-claude/wif-providers/github-actions#restrict-which-workflows-can-authenticate) para saber como delimitar essas claims com segurança.

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

Seja tão específico quanto a carga de trabalho permitir. Afrouxe `subject_prefix` para `repo:your-org/your-repo:*` (combinado com uma restrição `claims.ref`) somente se a regra precisar corresponder a vários tipos de evento do mesmo repositório, porque o segmento final de `sub` varia entre eventos `ref:...`, `environment:...` e `pull_request`.

## Obtenha e use um token

Defina as variáveis de ambiente de federação no job e chame o SDK normalmente. `Anthropic()` (typescript: `new Anthropic()`; csharp: `new AnthropicClient()`; go: `anthropic.NewClient()`; java: `AnthropicOkHttpClient.fromEnv()`; php: `new Client()`; ruby: `Anthropic::Client.new`) lê `ANTHROPIC_IDENTITY_TOKEN_FILE`, troca o JWT na primeira solicitação e atualiza o token de acesso automaticamente antes que ele expire.

<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

  # Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  # do ambiente do job.
  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";

  // Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  // do ambiente do job.
  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
  // Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  // do ambiente do job.
  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#
  // Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  // do ambiente do job.
  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
  # Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  # do ambiente do job.
  ant messages create \
    --model claude-opus-5-5 \
    --max-tokens 1024 \
    --message '{role: user, content: "Hello, Claude"}'
  ```

  ```php PHP
  use Anthropic\Client;

  // Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  // ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  // do ambiente do job.
  $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"

  # Lê ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID,
  # ANTHROPIC_SERVICE_ACCOUNT_ID, ANTHROPIC_WORKSPACE_ID e ANTHROPIC_IDENTITY_TOKEN_FILE
  # do ambiente do job.
  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>

Cada token de identidade emitido pelo GitHub expira aproximadamente cinco minutos após a emissão. O endpoint de solicitação de token (`ACTIONS_ID_TOKEN_REQUEST_URL`) permanece válido durante todo o job, portanto você pode obter um token novo a qualquer momento. O SDK troca o token no primeiro uso e armazena em cache o token de acesso da Anthropic resultante. Para jobs que executam por mais tempo do que a vida útil do token da Anthropic, o SDK relê `ANTHROPIC_IDENTITY_TOKEN_FILE` a cada atualização, então execute novamente a etapa de obtenção periodicamente (ou envolva-a em um loop em segundo plano) para manter o arquivo atualizado. Como alternativa, exceto em Java, passe ao SDK um provedor de token que chame `ACTIONS_ID_TOKEN_REQUEST_URL` diretamente em vez de usar o caminho do arquivo.

## Verifique a configuração

Uma troca bem-sucedida retorna um `access_token` começando com `sk-ant-oat01-` e um valor `expires_in` em segundos. Uma troca negada retorna um `401` `authentication_error` opaco com a mensagem fixa `Authentication failed`, independentemente de qual verificação falhou; na maioria dos casos, o motivo da negação é registrado na entrada da tentativa na [página de histórico de autenticação](https://platform.claude.com/settings/workload-identity-federation?tab=history) no Claude Console, e [Solucionar problemas de uma troca com falha](https://platform.claude.com/docs/pt-BR/manage-claude/wif-reference#troubleshoot-a-failed-exchange) percorre as verificações em ordem. A causa mais comum do lado do GitHub Actions é o formato da claim `sub` não corresponder (seu segmento final varia entre eventos `ref:...`, `environment:...` e `pull_request`); a entrada do histórico mostra o motivo `match_subject_prefix`.

## Restrinja quais workflows podem se autenticar

<Warning>
  Um `subject_prefix` de `repo:your-org/*` sozinho corresponde a todos os repositórios da sua organização e, sem uma restrição `ref`, também corresponde a execuções `pull_request` disparadas a partir de forks. Qualquer pessoa que possa abrir um pull request em um repositório correspondente poderia obter um token federado da Anthropic.
</Warning>

Restrinja o bloco `match` da regra ao escopo mais estreito que atenda ao seu caso de uso:

* **Fixe em um único repositório:** Use `subject_prefix: "repo:your-org/your-repo:*"` para que outros repositórios da organização não correspondam.
* **Fixe em uma branch protegida:** Adicione `"ref": "refs/heads/main"` (ou sua branch de release) em `claims` para que execuções de pull request e branches de feature não correspondam.
* **Fixe o proprietário explicitamente:** Adicione `"repository_owner": "your-org"` em `claims` como uma verificação de defesa em profundidade contra casos extremos de análise de `sub`.
* **Fixe em um ambiente de implantação:** Para jobs de deploy, faça a correspondência com `subject_prefix: "repo:your-org/your-repo:environment:production"` e controle esse ambiente com revisores obrigatórios no GitHub.

## Próximos passos

* [Workload Identity Federation](https://platform.claude.com/docs/pt-BR/manage-claude/workload-identity-federation): passo a passo completo de configuração, variáveis de ambiente e precedência de credenciais.
* [Autenticação](https://platform.claude.com/docs/pt-BR/manage-claude/authentication): como a federação se compara às chaves de API.
