Solved cross-platform npm registry account moderate
npm publish fails because 2FA is a passkey and there's no OTP to enter
Symptom npm publish wants a one-time password, but your 2FA is a passkey (Touch ID / security key) with no authenticator app, so there's no code to type; publish fails or 401s.
Publishing to npm stalled because the account’s 2FA is a WebAuthn passkey (Touch ID / security key), with no TOTP authenticator app. Interactive npm publish expects to prompt for a 6-digit OTP, but there’s no code to enter — a passkey can’t produce one — so the publish either hangs waiting for input or fails with a 401.
The fix
Use a Classic → Automation token, which is designed for CI/non-interactive publishing and bypasses the 2FA prompt:
- npmjs.com → Access Tokens → Generate New Token → Classic Token → Automation.
- Copy the token and put it in
~/.npmrc:
//registry.npmjs.org/:_authToken=npm_xxxxxxxxxxxxxxxxxxxx
npm publishnow works with no OTP prompt.
If it’s a scoped org package
Two extra gotchas that produce a confusing 402/404-on-PUT:
- Scoped packages (
@org/name) default to private, which fails on a free org. Make it public:
{
"publishConfig": { "access": "public" }
}
npm publish --access public
- A GitHub org is not an npm org. Publishing an unscoped name pushes it under your personal account, not the org. The package name must be scoped
@org/nameto land in the npm org.
Don’t get burned later
- npm tokens expire after ~90 days. If a publish that used to work suddenly 401s, or PUT returns 404, the token expired — mint a fresh Automation token and update
~/.npmrc. - Use a
"files"allowlist inpackage.json, not just.npmignore. Without it, npm packs the entire working directory — it’s easy to accidentally ship tens of MB of local junk into the tarball.