发生了什么?
2025 年 12 月 9 日,npm 正式永久撤销了所有 Classic Token。与此同时,npm 引入了基于会话的认证(2 小时有效期)和新的 CLI Token 管理方式。这意味着:
- 所有 Classic Token 立即失效,无法恢复
npm login现在只发放 2 小时的短期会话令牌- CI/CD 场景推荐使用 Granular Access Token 或 OIDC Trusted Publishing
我的 GitHub 项目 CI 工作流自然也挂了 —— 因为 Secrets 里存的还是那个已被吊销的 Classic Token。
Trusted Publishing 是什么?
简单说,Trusted Publishing 利用 OIDC(OpenID Connect) 协议,让 CI/CD 平台(如 GitHub Actions)直接与 npm 交换短期凭证来发布包,完全不需要存储任何 npm token。
优势很明显:
- 没有长期 Token,不存在泄露风险
- 自动附带 Provenance(来源证明),包的构建来源可追溯
- 配置一次,后续发版无需维护密钥
目前支持 GitHub Actions(GitHub-hosted runners)和 GitLab CI/CD(shared runners),不支持自托管 runner。
版本要求:npm CLI ≥ 11.5.1,Node.js ≥ 22.14.0。
迁移步骤
1. 在 npmjs.com 配置 Trusted Publisher
进入目标 Package 的 Setting 页面,找到 Trusted Publisher 部分,填写:
- Owner:GitHub 用户名或组织名
- Repository:仓库名
- Workflow filename:工作流文件名(含
.yml扩展名,如publish.yml) - Environment(可选):GitHub 部署环境名
注意:文件名、仓库名区分大小写,必须与 workflow 文件完全一致。
2. 配置 GitHub Actions Workflow
核心改动就两点:声明 OIDC 权限、直接用 npm publish。
以下是我最终可用的 workflow(使用 pnpm):
name: publish
on:
release:
types: [published, released]
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC 必需
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 24
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --no-frozen-lockfile
- name: Build
run: pnpm run build
- name: Publish
if: github.repository == 'wayjam/picgo-plugin-s3'
run: pnpm publish --no-git-checks --ignore-scripts --provenance --access public
不再需要 NPM_TOKEN、不再需要 NODE_AUTH_TOKEN,也不再需要 JS-DevTools/npm-publish 这类第三方 Action。直接原生 npm publish / pnpm publish 就行。
注意事项与故障排除
package.json 必须包含 repository 字段
npm 的 Provenance 机制会校验发布环境与包元数据是否匹配。如果 package.json 中没有 repository 字段(或值为空),会返回 422 错误:
npm error 422 Unprocessable Entity - PUT https://registry.npmjs.org/<package-name>
- Error verifying sigstore provenance bundle: Failed to validate repository information:
package.json: "repository.url" is "", expected to match
"https://github.com/<owner>/<repo>" from provenance
确保 package.json 中有正确且与 npm 配置一致的 repository 字段:
"repository": {
"type": "git",
"url": "git+https://github.com/<owner>/<repo>.git"
}
pnpm 添加 --no-git-checks(可选)
pnpm publish 默认会执行 git 检查,拒绝从非主分支或脏工作区发布。而 GitHub Actions 的 actions/checkout 默认是 Detached HEAD 状态,会直接触发该检查失败。如果是非 main/master 发布则需加上这个参数:
pnpm publish --no-git-checks --ignore-scripts --provenance --access public
Workflow 必须显式声明权限
没有在 job 级别声明 permissions,OIDC token 交换会直接失败。以下两项缺一不可:
permissions:
id-token: write # 用于 OIDC token 交换
contents: read # 用于 checkout 代码
报错 “Access token expired or revoked”
看到这个错误不一定是 token 问题。更常见的原因是:npm 网页端填写的 workflow 文件名与实际文件名不一致(包括大小写、.yml/.yaml 扩展名),导致 OIDC 验证时仓库/workflow 信息比对失败。逐项核对 npm 设置中的 owner、repo、workflow filename 即可。
清理
配置成功并验证发布正常后:
- 从 GitHub 仓库的 Settings → Secrets 中删除旧的
NPM_TOKEN - 如果之前用的是
JS-DevTools/npm-publish,可以从 workflow 中移除该依赖 - 在 npm 包设置中,可以启用 “Require two-factor authentication and disallow tokens” 进一步加固安全