npm trusted publishingをClaude Codeで組む — トークン不要でprovenance付き
npmのtrusted publishingで、公開トークンを持たずGitHub Actionsから公開するworkflowを組みます。id-token権限とNPM_TOKENを消す差分をClaude Codeに書かせる手順です。
npmのtrusted publishing(信頼された発行元)は、CIのOIDC認証でnpmに公開する仕組みです。長期間有効な公開トークンをリポジトリのsecretに置かずに済みます。GitHub Actionsから公開した場合は、provenance(どこでビルドされたかの証明)も自動で付きます。
workflowの書き換え自体は数行です。ただし登録項目の綴りが1字違うだけで、公開の瞬間まで誤りが表に出ません。Claude Codeには差分を書かせ、npm側の登録と初回の公開は人が確かめる、という分担で進めると事故が減ります。
trusted publishingで何が変わるか
従来は、npmで発行した自動化用トークンをNPM_TOKENとしてsecretに保存し、publishステップで読み込んでいました。trusted publishingでは、npmがGitHub Actionsの特定のworkflowを信頼する設定を持ち、publish時に短命の認証情報をその場で受け取ります。npm CLIはOIDC環境を自動で検出し、従来のトークンより先にOIDCを試します。
トークン方式とtrusted publishingの違い
トークン方式
長期有効なトークンをsecretに保存します。ログへの露出や手動のローテーションが課題になります。
trusted publishing
公開のたびに短命で、workflow固有の認証情報を使います。取り出して再利用できません。
使える範囲には条件があります。
- npm CLIは11.5.1以降、Nodeは22.14.0以降が必要です
- 対応するCIはGitHub Actions(GitHubホストランナー)、GitLab CI/CD(GitLab.comの共有ランナー)、CircleCI(クラウド)です。セルフホストランナーは対象外です
- 1つのパッケージに登録できる発行元は最大10件です
作業は4段階に分かれる
トークンを消すまでの流れ
- 1
npmのパッケージ設定で発行元を登録する
npmjs.comのパッケージ設定にある「Trusted Publisher」で、GitHub Actionsを選び、リポジトリとworkflowファイル名を入力します。
- 2
workflowにid-token権限を足し、トークンを消す
Claude Codeに書かせる差分は、この段階です。
- 3
初回の公開で設定を確定させる
新しい設定は、作成から2日以内に最初の公開を成功させる必要があります。
- 4
動いたらトークンを締める
自動化用トークンの失効と、トークン公開の禁止設定に進みます。
順序が大切です。npmの手順書は、先に発行元を設定して動作を確かめ、そのあとでトークンを制限し、不要になった自動化トークンを失効させる流れを勧めています。
npm側の登録項目は人が入力する
登録画面はnpmjs.comの操作なので、Claude Codeには任せません。GitHub Actionsで入力する項目は次のとおりです。
| 項目 | 必須 | 入れる値 |
|---|---|---|
| Organization or user | 必須必須 | 入れる値GitHubのユーザー名かOrganization名 |
| Repository | 必須必須 | 入れる値リポジトリ名 |
| Workflow filename | 必須必須 | 入れる値publish.ymlのようなファイル名のみ。拡張子を含める |
| Environment name | 必須任意 | 入れる値GitHub Environmentsを使う場合 |
| Allowed actions | 必須任意 | 入れる値npm publishとnpm dist-tagを許すかの選択 |
Workflow filenameは、パスではなくファイル名だけを書きます。.ymlか.yamlの拡張子が必要で、ファイル自体は.github/workflows/に置きます。全項目で大文字と小文字が区別されます。
注意したいのが「Allowed actions」です。2026年9月3日より後に作った設定は、npm stage publishが自動で許可されます。npm publishで直接公開するかは選択制です。workflowでnpm publishを走らせるなら、登録時にこの許可を選んだかを確かめます。
npm stage publishを使うと、公開の前にメンテナーが2要素認証で承認する段階が入ります。承認に使うnpm stage approveなどは、対話的な認証が必要なため、OIDCトークンでは実行できません。
Claude Codeに渡す指示
差分を書かせる前に、リポジトリに規約を置きます。次はCLAUDE.mdに足す断片の例です。
## npm公開のworkflow
- 公開は `.github/workflows/publish.yml` だけで行う
- 公開用のトークン(`NPM_TOKEN` / `NODE_AUTH_TOKEN`のsecret)は使わない
- publishを含むジョブには `permissions: id-token: write` と `contents: read` を付ける
- setup-nodeはNode 24、`registry-url`を指定し、キャッシュは使わない
- ローカルで `npm publish` を実行しない。確認は `--dry-run` までそのうえで、次のように依頼します。
.github/workflows/publish.yml を、npmのtrusted publishingに書き換えて。
NPM_TOKEN の参照を全部消し、id-token: write を足す。
package.json の repository.url が GitHub のリポジトリ URL と一致するかも確かめて。
変更前後の差分を見せて。公開コマンドは実行しない。Claude Codeが読むのは手元のファイルなので、npm側の登録内容は見えません。workflowファイル名とnpmに登録した名前の一致は、人が目で突き合わせます。
書き換えるworkflowの完成形
npmのドキュメントにある例を、タグのpushで動く形に当てはめるとこうなります。
name: Publish Package
on:
push:
tags:
- 'v*'
permissions:
id-token: write # OIDCに必要
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false # リリースではキャッシュを使わない
- run: npm ci
- run: npm run build --if-present
- run: npm test
- run: npm publishトークン方式から移すときに消す箇所は、publishステップのenvにあるNODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}です。npmの例は、publishステップに認証用の環境変数を持ちません。必要なのはid-token: writeだけです。
--provenanceを足す必要はありません。GitHub ActionsかGitLab CI/CDからtrusted publishingで公開すると、provenanceは既定で自動生成されます。
provenanceが付かない条件
自動生成されるのは、次の3つがすべて当てはまるときです。
- trusted publishing(OIDC)で公開している
- 公開リポジトリから公開している
- 公開パッケージを公開している
プライベートリポジトリからは、パッケージが公開でもprovenanceは生成されません。CircleCIでも対象外です。
依存にprivateなパッケージがあるとき
trusted publishingはnpm installのための認証ではありません。private依存の取得に失敗するなら、npm ciのステップだけに読み取り専用トークンを渡します。publishステップにはトークンを渡しません。
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_READ_TOKEN }}
- run: npm publish # OIDCを使うのでトークン不要dry-runで確かめられる範囲
公開前の確認にはdry-runが使えます。Claude Codeに手元でnpm publish --dry-runを実行させ、公開されるファイルの一覧とpackage.jsonの中身を確認させます。
dry-runで見えるのは成果物の中身までです。trusted publisherの設定が正しいかは別の問題です。npmの注記どおり、設定は保存時に検証されず、誤りは公開を試みたときにしか出ません。
そこで、確認を2段に分けます。
| 確認したいこと | 確かめる方法 |
|---|---|
| 公開されるファイルが想定どおりか | 確かめる方法手元のnpm publish --dry-run |
NPM_TOKENの参照が残っていないか | 確かめる方法grep -rn "NPM_TOKEN|NODE_AUTH_TOKEN" .github |
repository.urlが一致しているか | 確かめる方法package.jsonをClaude Codeに読ませる |
| 登録内容とworkflowが一致しているか | 確かめる方法実際のタグpushによる初回公開 |
2段目の初回公開は、登録から2日以内に成功させます。2日を過ぎると設定は失効し、編集もできなくなります。削除して作り直すことになるので、登録するのは公開できる状態になってからです。
ENEEDAUTHが出たときの切り分け
認証に失敗するとUnable to authenticate(ENEEDAUTH)が出ます。npmの案内に沿って、上から順に確かめます。
ENEEDAUTHの切り分け
- Qnpmの登録とworkflowのファイル名は、拡張子まで一字違わず一致しているか?答えが直す答えがはい
大文字と小文字も区別されます。登録内容は編集できないので、削除して作り直します。
- QGitHubホストランナーで動いているか?答えがランナーを変える答えがはい
セルフホストランナーは対象外です。
- Qworkflowに`id-token: write`があるか?答えが足す答えがはい
親と子のworkflowを分けているなら、両方に必要です。
それでも失敗するとき
package.jsonのrepository.urlが、GitHubのリポジトリと完全に一致しているかを確かめます。フォークでは、この値が元のリポジトリのままになりがちです。
呼び出し関係にも落とし穴があります。workflow_callで別のworkflowを呼ぶ構成や、workflow_dispatchの手動実行では、npmが検証するのは呼び出し元のworkflow名です。publishコマンドを含むファイルの名前とは限りません。登録するファイル名がずれる原因になります。
Claudeの実行環境と公開権限を分ける
この記事の構成は、公開の権限をClaude Codeの手から離す設計でもあります。トークンがリポジトリのsecretにも手元にも無ければ、Claude Codeがnpm publishを実行しても認証できません。
Claude Codeの権限ルールでnpm publishを止める方法は、Changesetsの記事で扱っています。trusted publishingと組み合わせると、止める線が増えます。
- Claude Code側:
permissions.denyでnpm publishを止める - npm側: 発行元をタグpushで動くworkflowに限る
- GitHub側: タグの作成権限を絞る
npmの手順書は、追加の対策としてデプロイ環境の承認要件、タグ保護ルール、発行元設定の定期的な見直し、使っていない公開トークンの削除を挙げています。
GitHub上でClaudeを動かすworkflowを同じリポジトリに持つなら、その権限設定は別物です。Claude Code GitHub Actionは、既定のGitHub App認証のためにid-token: writeを必要とします。公開用のworkflowとは別のファイルに分けておくと、npmに登録するファイル名も迷いません。設定の全体像はworkflow YAMLの記事にあります。
動いたらトークンを締める
初回の公開が通ったら、次の順で締めます。
- パッケージのSettings → Publishing accessで「Require two-factor authentication and disallow tokens」を選び、保存する
- 使っていない自動化トークンを失効させる
- GitHubのsecretから
NPM_TOKENを削除する
「disallow tokens」が止めるのは従来のトークン認証だけです。trusted publisherはOIDCトークンを使うため、設定後も動き続けます。
さらに厳しくするなら、発行元をnpm stage publishのみの許可にします。CIからの公開はすべてステージングを通り、メンテナーが2要素認証で承認するまで公開されません。
つまずきやすい点
| 症状 | 原因と対処 |
|---|---|
| 設定が失効していた | 原因と対処登録から2日以内に初回公開が成功していない。削除して作り直す |
公開できるのにdist-tagが失敗する | 原因と対処Allowed actionsのnpm dist-tagが無効。dist-tagの操作にはnpm CLI 11.21.0以降(または12.2.0以降)も要る |
| provenanceが付かない | 原因と対処プライベートリポジトリ、またはCircleCIからの公開 |
private依存のnpm ciが失敗する | 原因と対処読み取り専用トークンをnpm ciにだけ渡す |
| 登録を直したい | 原因と対処既存の設定は変更できない。削除して作り直す |
まとめ
trusted publishingへの移行は、npmでの発行元の登録、workflowへのid-token: write、publishステップからのトークン削除の3点です。Claude Codeには差分とpackage.jsonの突き合わせを任せられます。登録の綴りと初回公開の成否は、人が確かめる領域として残してください。移行が終わったら、トークンを失効させるところまで済ませて完了です。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。