一次 npm 更新强制2FA导致的发布失败的排查:403、2FA、Recovery Code、Granular Token 的混乱体验

最近在更新发布自己的一个 npm 包(branch-commit-compare)时踩了一堆坑。问题本身不复杂,但 npm 新旧验证体系在 UI 和流程上混杂一起,导致排查成本远高于必要水平。这里记录一下整个过程,避免别人重复踩坑。


背景

我本地执行:

复制代码
npm publish

结果直接报:

dart 复制代码
npm ERR! 403 Forbidden - PUT https://registry.npmjs.org/xxx
Two-factor authentication or granular access token with bypass 2fa enabled is required to publish packages.

很明确:npm 要求 2FA 或具有 bypass-2FA 权限的 token 才允许发布。问题在于 ------ 我当时的 2FA 状态看起来"不完整"。


一、UI 误导:npm 只给我一个「Security Key」选项

进入 npm 账户的 Security 页面 → Enable 2FA,看到的 2FA 方式只有:

Security Key(USB/NFC、生物识别等)

正常情况下,npm 应该同时提供:

  • Authenticator App(TOTP)
  • Security key(FIDO U2F)
  • Recovery codes

但在我这里,点击 Enable 2FA 直接跳到 Security Key,没有 TOTP 选项。

这会带来一个明显问题:

npm CLI 的 --otp=xxxxxx 只能输入 TOTP 码,不能输入恢复码、不能输入 security-key 相关内容。

也就是说:只启用 Security Key = 无法在 CLI 完成 publish。


二、我以为自己拿到的是「秘钥」,实际上那是 Recovery Codes

复制代码
e496c18fe4b39b0e2e1d2d4c7958c561fd3a2526f31ce7aea8394413b1826576
061baf4f296ea7e94c416eb9be80ecd47843ae7b957916f7d788d7310cefc053
4c7feaaca38231ca76222bab37eea9ff1dc69ccf90398900025c4dd03226002b
1886537d1acf213f1ea27329bd7ecdc6e6934397a55a1b1d5882698617f738ed
8b6abe5645ffb5e09d6b6aad2955d8ac9c64bf971751845cbf2afd453476473d

UI 只显示一串普通文本,把它描述成"安全密钥"。但实际那是 Recovery Codes(一次性备份码),不是 TOTP Secret,也不是 token。

把换行删掉、合并成一行都没用,它压根不是 TOTP。

这导致我误以为 CLI 能用它 publish → 当然失败。


三、npm profile get 暴露核心真相

执行:

arduino 复制代码
npm profile get

返回:

matlab 复制代码
two-factor auth │ auth-and-writes

含义:

  • 你已经启用了 2FA,但只启用了 写操作保护
  • npm 要求:发布时必须提供 TOTP
  • Recovery Code 和 Security Key 都不能替代 TOTP

结论:你的 2FA 配置不完整,CLI 肯定 403。


四、可行的解决路径:创建 Granular Token 并开启 bypass 2FA

既然 npm CLI 强制需要 TOTP,而 UI 又不给你配置 TOTP,那就只能走另一条路:

1. 创建 Granular Access Token

进入 npm → 头像 → Access Tokens → Create New Token

选择:

  • 类型:Granular / Automation Token
  • 权限:选择你要 publish 的包
  • 关键:勾选 "Bypass two-factor authentication"

创建后会出现真正的一次性 token(长字符串),这才是发布用的。

2. 写入本地 ~/.npmrc

bash 复制代码
echo "//registry.npmjs.org/:_authToken=你的token" >> ~/.npmrc

3. 再次发布

复制代码
npm publish

→ 一次通过。


五、根因:npm 的验证系统正在剧烈切换

npm 现在要求:

  • 经典 token 全部废弃
  • granular token 成为唯一可用的 token
  • granular token 默认需要 2FA
  • 而 2FA 又分 TOTP / security key
  • 但 UI 渐进式上线,部分用户只能看到 security key
  • CLI 又要求 TOTP

这就造成一个现象:

你启用了"半套"2FA,UI 显示正常,但 CLI 无法完成发布。


六、最终解决方案总结

  1. npm profile get 显示 auth-and-writes → CLI 必须 OTP
  2. UI 只给你 Security Key,没有 TOTP → CLI 永远无法输入正确 OTP
  3. Recovery Code 不是 OTP → 无效
  4. 唯一可行方法 → 创建带 bypass-2FA 的 granular token
  5. 写入本地 .npmrc 后发布即可

七、给后来者的建议

如果你正在启用 npm 的 2FA:

  • 一定要启用 TOTP(Authenticator App)
    而不是只启用 Security Key (但是官方只给了这种方式)
  • Granular Token 是目前唯一不会踩坑的方式(特别是 CI/CD)
  • 不要被恢复码误导,它不是 OTP
  • 25年12月9号强制必须使用2FA或者绕过2FA的token 我今天12月12太多人在操作了,官网巨卡无比

结语

npm 的验证体系正在重构,UI 不统一、流程半旧半新,是这次踩坑的根本原因。如果你遇到类似的 403 + 要求 2FA,又找不到 TOTP,多半和我一样卡在了"只有 Security Key"这个界面。

解决方法就是:绕开 2FA,使用带 bypass 权限的 granular token 发布。

相关推荐
卸任12 小时前
Vibe coding工具使用心得
前端·ai编程
brien913 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance13 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M13 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写13 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李13 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易13 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马13 小时前
前沿视界
前端
kyriewen13 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易14 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员