# 信頼できるパブリッシャー

**Push to the Hub from CI without storing an `HF_TOKEN` secret.**

CIジョブは、CIプロバイダーから発行された短期有効なOpenID Connect（OIDC）トークンを使用してHugging Faceにその身元を証明し、引き換えに短期有効なHugging Faceトークンを取得します。シークレットとして保存したりローテーションしたりするHFトークンは不要です。

| | Personal Access Token | 信頼できるパブリッシャー |
| --- | --- | --- |
| ライフタイム | 取り消し時まで | 1時間 |
| ストレージ | CIシークレット | 保存するものはありません |
| 回転 | マニュアル | 自動的、すべての実行 |
| リークした場合 | 取り消しを行うまで有効 | 最大で約1時間、1つのリポジトリに限定 |

Trusted Publishers は、PyPI の [Trusted Publishers](https://docs.pypi.org/trusted-publishers/) や [npm の Trusted Publishing](https://docs.npmjs.com/trusted-publishers) と同じコンセプトです。

## クイックな例: GitHub Actionsからモデルを公開する

HF Hub上で`acme/awesome-model`を管理しており、外部ホスティングの`acme/awesome-model-training`リポジトリ（GitHub、GitLab、またはOIDC準拠の任意のプロバイダー）でCIを実行して新しいチェックポイントをプッシュしたいと考えています。`HF_TOKEN`シークレットは不要です。

### 1. Hubで信頼できるパブリッシャーを設定します

`https://huggingface.co/acme/awesome-model/settings` で **Trusted Publishers** を開き、以下を追加します:

- **プロバイダー**: GitHub Actions
- **クレーム**（交換が成功するにはすべて一致する必要があります）：
  - `repository` = `acme/awesome-model-training`
  - `branch` = `main`
  - `workflow` = `publish.yml`

> [!TIP]
> `repository` 単体では、パブリッシャーを GitHub リポジトリにスコープします。ブランチやワークフローファイルにも固定するには、`branch` および/または `workflow` を追加してください（推奨）。

### 2. ワークフローを GitHub リポジトリに追加します

`.github/workflows/publish.yml`:

```yaml
name: Publish to Hugging Face

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  publish:
    runs-on: ubuntu-latest

    permissions:
      id-token: write  # required so the job can request an OIDC token
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Install the hf CLI
        run: |
          curl -LsSf https://hf.co/cli/install.sh | bash
          echo "$HOME/.local/bin" >> "$GITHUB_PATH"

      - name: Upload checkpoint
        env:
          # The HF repo to publish to. For non-model repos, prefix accordingly:
          #   datasets/acme/awesome-dataset, spaces/acme/awesome-space, kernels/acme/awesome-kernel
          HF_OIDC_RESOURCE: acme/awesome-model
        run: hf upload acme/awesome-model ./checkpoint . --commit-message "Publish from ${GITHUB_SHA::7}"
```

以上です。GitHub Actions 上では、`hf` CLI（`huggingface_hub>=1.19.0`）がプロバイダーを検出し、交換を実行し、結果として得られたトークンを自動的に使用します。設定するのは `HF_OIDC_RESOURCE` だけです。

> [!TIP]
> 1回の実行で複数のリポジトリに公開する場合（モデル**と**データセットなど）は、`HF_OIDC_RESOURCE`をステップごとに設定し、各トークンがそのステップでプッシュするリポジトリにスコープが設定されるようにしてください。

#### その他のCIプロバイダー

現時点では、`hf` CLIはGitHub ActionsでのみネイティブにIDトークンを発行します。GitLab、CircleCI、Bitbucket、その他のプロバイダーでは、IDトークンを自分で発行し（[サポートされているCIプロバイダー](#supported-ci-providers)を参照）、`HF_OIDC_ID_TOKEN`経由で渡します。CLIはこれを直接交換します。

```yaml
# GitLab CI (.gitlab-ci.yml)
publish:
  id_tokens:
    HF_ID_TOKEN:
      aud: https://huggingface.co
  script:
    - curl -LsSf https://hf.co/cli/install.sh | bash
    - export PATH="$HOME/.local/bin:$PATH"
    - HF_OIDC_ID_TOKEN="$HF_ID_TOKEN" HF_OIDC_RESOURCE="acme/awesome-model" hf upload acme/awesome-model ./checkpoint .
```

完全な動作する例:

- GitHub Actions — [`github.com/coyotte508/publish-to-hf`](https://github.com/coyotte508/publish-to-hf)
- GitLab CI — [`gitlab.com/coyotte508/publish-to-hf`](https://gitlab.com/coyotte508/publish-to-hf)

## 2つのタイプ: リポジトリの公開者とCI/CDのアイデンティティ

| フレーバー | 設定日 | 得られるもの | これを使用して… |
| --- | --- | --- | --- |
| **リポジトリの信頼できるパブリッシャー** | リポジトリの**Settings → Trusted Publishers** | **その1つのリポジトリへの書き込みアクセス**（または[読み取り専用アクセス](#read-only-repo-publishers)）を持つトークン | CIからモデル、データセット、Space、カーネル、バケットを公開するか、プライベートなものを取得します |
| **アカウントのCI/CDアイデンティティ** | アカウントの[**認証設定 → CI/CD アクセス**](https://huggingface.co/settings/authentication#ci-cd-access) | `gated-repos`スコープを持つ読み取り専用トークン、およびオプトインした場合の`inference-api` | アクセス権限を持つ**ゲート付きリポジトリ**を読み取り、レート制限を使用し、必要に応じてCIからInference Providersを呼び出します |

両方のトークンは60分後に失効します。Hubリポジトリの信頼できるパブリッシャーを管理するには、そのリポジトリに**Write**ロールが必要です。

### CIからゲート付きリポジトリにアクセスする

ゲート付きリポジトリの*読み取り*のみが必要な場合（ジョブからモデルをダウンロードするなど）、特定のリポジトリではなく、アカウントの[**Authentication settings → CI/CD Access**](https://huggingface.co/settings/authentication#ci-cd-access)にCI/CDアイデンティティを追加し、リソースとして**username**を使用してください。

**GitHub Actions**では、`hf` CLIが交換を代行します。`HF_OIDC_RESOURCE`を設定するだけです。

```yaml
      - name: Download a gated model
        env:
          HF_OIDC_RESOURCE: your-hf-username
        run: hf download acme/gated-model
```

**他のプロバイダー**では、IDトークンを自分で発行し（[他のCIプロバイダー](#other-ci-providers)を参照）、`HF_OIDC_ID_TOKEN`を介して渡します：

```bash
# $ID_TOKEN is the OIDC token your provider minted (e.g. $HF_ID_TOKEN on GitLab)
HF_OIDC_ID_TOKEN="$ID_TOKEN" HF_OIDC_RESOURCE="your-hf-username" hf download acme/gated-model
```

生成されたトークンは、アクセス権限を持つゲート付きリポジトリを読み取ることができ、アカウントのレート制限が適用されます。このトークンは**書き込み**を行うことはできず、**プライベートリポジトリ**を読み取ることもできません。CIからプライベートリポジトリを取得するには、代わりに[読み取り専用リポジトリパブリッシャー](#read-only-repo-publishers)を使用してください。

> [!TIP]
> トークン自体が必要ですか（`curl`、`git clone`、または`HF_TOKEN`を読み取るツールで使用する場合）？`hf auth token`を実行すると、交換が行われ、短期間有効なトークンが標準出力に表示されます：
>
> ```yaml
>       - name: Get a short-lived HF token
>         env:
>           HF_OIDC_RESOURCE: your-hf-username  # or a repo, e.g. acme/awesome-model
>         run: echo "HF_TOKEN=$(hf auth token)" >> "$GITHUB_ENV"
> ```
>
> CI/CDアイデンティティとリポジトリの発行者の両方で動作します。トークンは、`HF_OIDC_RESOURCE`が指す対象にスコープが設定されます。

### 読み取り専用リポジトリの公開者

デフォルトでは、リポジトリの信頼済みパブリッシャーは、そのリポジトリにプッシュできるトークンを発行します。ワークロードがリポジトリの*pull*のみを必要とする場合（CIジョブや独自のOIDCトークンを発行する外部プラットフォームから、プライベートなモデルやデータセットをダウンロードするなど）、パブリッシャーを追加する際に**Read-only**にチェックしてください。これにより、交換されたトークンはリポジトリの内容を読み取れますが、書き込みはできなくなります。また、リストには**Read-only**バッジが表示されます。この機能は、モデル、データセット、Spaces、カーネル、バケットで動作します。

交換自体は変更されていません。`HF_OIDC_RESOURCE`（または`resource`）をリポジトリに設定してください。

```yaml
    permissions:
      id-token: write  # required so the job can request an OIDC token

    steps:
      - name: Download a private model
        env:
          HF_OIDC_RESOURCE: acme/private-model
        run: hf download acme/private-model
```

他のパブリッシャー設定と同様に、この権限は作成時に固定されます。変更するには、パブリッシャーを削除してから再度追加してください。

### CIからInference Providersを呼び出す

CI/CDアイデンティティのトークンは、デフォルトで読み取り専用です。Inference Providersの呼び出しも許可するには、アイデンティティの追加時に**Allow Inference Providers calls**にチェックを付けてください。これにより、交換されたトークンは`gated-repos`に加えて`inference-api`スコープを持ち、リストには**Inference**バッジが表示されます。

推論の利用は、ご自身でリクエストを発行した場合と同様に、**アカウントに請求**されます。そのため、有効化する前にクレームを厳密に固定してください（`repository` *および* `branch`、および/または `workflow`）。

```yaml
      - name: Run inference from CI
        env:
          HF_OIDC_RESOURCE: your-hf-username
        run: |
          export HF_TOKEN="$(hf auth token)"
          python inference_script.py
```

リポジトリの公開者は対象外です。トークンはリポジトリスコープに限定されており、Inference Providersを呼び出すことができません。この機能は作成時に固定されます。変更するには、アイデンティティを削除してから再度追加してください。

## サポートされているCIプロバイダー

設定UIには、以下のプロバイダー用のプリセットが同梱されていますが、OIDC準拠のプロバイダーであればすべて動作します（AWS、GCP、Buildkite、独自のIdPなど）。

| プロバイダー | 発行者 | IDトークンの取得方法 |
| --- | --- | --- |
| **GitHub Actions** | `https://token.actions.githubusercontent.com` | `permissions: id-token: write`を設定し、`audience=https://huggingface.co`を指定してメタデータエンドポイントを呼び出します。[ドキュメント](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)。 |
| **GitLab CI** | `https://gitlab.com`（またはセルフホストされた URL） | ジョブで`id_tokens: { HF_ID_TOKEN: { aud: https://huggingface.co } }`を宣言し、`$HF_ID_TOKEN`を読み取ります。[ドキュメント](https://docs.gitlab.com/ci/yaml/#id_tokens)。 |
| **CircleCI** | `https://oidc.circleci.com/org/<org-uuid>` | `$CIRCLE_OIDC_TOKEN_V2` を使用します（v2 ではプロジェクト設定でオーディエンスを設定できます）。[ドキュメント](https://circleci.com/docs/openid-connect-tokens/)。 |
| **Bitbucket Pipelines** | `https://api.bitbucket.org/2.0/workspaces/<workspace>/pipelines-config/identity/oidc` | ステップで`oidc: true`を設定し、`$BITBUCKET_STEP_OIDC_TOKEN`を読み取ります。[ドキュメント](https://support.atlassian.com/bitbucket-cloud/docs/integrate-pipelines-with-resource-servers-using-oidc/)。 |

IDトークンを取得した後、交換呼び出しはプロバイダー間で同一です。異なるのは、Hub側で設定する**claims**のみです。

## 仕組み

1. CIプロバイダーは、ジョブ（リポジトリ、ブランチ、ワークフローなど）を記述する短期有効な**OIDC IDトークン**を発行します。
2. ワークフローは、そのトークンを`POST`リクエストで`https://huggingface.co/oauth/token`に送信します。このとき、`resource`（アクセス対象のリポジトリまたはユーザー名）も一緒に送信します。
3. Hubは、そのリソース用に設定した発行者に対してトークンの署名とクレームを検証し、Hugging Faceトークンを返します。

```
┌──────────┐  1. mint ID token   ┌──────────┐  2. exchange   ┌────────────┐
│ CI job   │ ─────────────────▶  │ CI OIDC  │ ──────────────▶│ huggingface│
│          │                     │ issuer   │                │  /oauth/   │
│          │ ◀──────────────────────────────────────────────│  token     │
└──────────┘        3. short-lived HF token (valid 1 h)      └────────────┘
```

## APIリファレンス

エンドポイント、リクエスト、レスポンス

**エンドポイント:** `POST https://huggingface.co/oauth/token`、`Content-Type: application/json` を使用。

クライアント認証は不要です。OIDC IDトークンがリクエストを認証します。交換処理は[RFC 8693 — OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693.html)に従います。

**リクエストボディ:**

| フィールド | 必須 | 値 |
| --- | --- | --- |
| `grant_type` | はい | `urn:ietf:params:oauth:grant-type:token-exchange` |
| `subject_token_type` | はい | `urn:ietf:params:oauth:token-type:id_token` |
| `subject_token` | はい | CI プロバイダーから取得した生の OIDC ID トークン（JWT）です。`aud` クレームは、**必ず**`https://huggingface.co` である必要があります。 |
| `resource` | はい | Hubのリポジトリ（`namespace/name`、`datasets/namespace/name`、`spaces/namespace/name`、`kernels/namespace/name`、`buckets/namespace/name`）または、ユーザースコープのトークン用のHubの**username**（スラッシュなし）。 |

**成功レスポンス:**

```json
{
  "access_token":      "hf_jwt_…",   // "hf_oauth_…" for user resources
  "token_type":        "bearer",
  "expires_in":        3600,
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
}
```

**エラー** — OAuth 形式のボディを伴う `400 Bad Request`：

| `error` | なぜ |
| --- | --- |
| `invalid_request` | パラメータが欠落または不正な形式であるか、`resource`の形式が不正です。 |
| `invalid_grant` | リポジトリまたはユーザーが見つかりません。この発行者に一致する発行者がありません。設定されたクレームが一致しません。署名またはオーディエンスのチェックに失敗しました。アカウントがロックされています。 |

`hf` CLI が交換を実行する際、失敗が発生すると `error` コードと `(Request ID: …)` が表示されます。問題を報告する際は、ログ上で交換を追跡できるように、その Request ID を必ず含めてください。

## セキュリティモデル

- **トークンは短命です。** 交換時刻から60分間有効です。カウントダウンはワークフローの開始時ではなく、エンドポイントを呼び出した時点から始まります。リフレッシュトークンは存在しないため、長時間実行されるジョブでは再交換を行う必要があります。
- **リポジトリトークンはリポジトリ単位のスコープを持ちます。**`acme/awesome-model` 用のトークンは `acme/anything-else` にアクセスできません。プッシュは、元の発行者とサブジェクトへの参照を伴う合成の `[OIDC]` システムユーザーに帰属されます。読み取り専用のパブリッシャーからのトークンは、そのリポジトリを読み取るのみ可能です。
- **ユーザー トークンは読み取り専用です。** デフォルトでは `gated-repos` スコープのみが適用され、書き込み、プライベート リポジトリへのアクセス、アカウント管理はできません。オプションの `inference-api` スコープを追加すると、Inference Providers への呼び出しが可能になります（アカウントに請求されますが）、それでもなお書き込みやプライベート リポジトリへのアクセスはできません。
- **クレームは完全一致、またはプロバイダーのプリセットが必要な場合はプレフィックス一致で照合されます**（GitHubの`workflow_ref`）。正規表現は使用されません。
- **監査ログ。**パブリッシャーの追加または削除はログに記録され、正常に完了した交換では最終使用時刻が更新されます。

## 関連項目

- [ユーザーアクセストークン](./security-tokens) — 人間やワンオフスクリプト向けの適切な選択肢
- [OAuth / HF でのサインイン](./oauth) — インタラクティブなフローで使用される同じ `/oauth/token` エンドポイント
- [GitHub ActionsによるSpacesの管理](./spaces-github-actions)
- [Hub 用の GitHub Actions 統合](./repositories-github-actions)

