[BUG] Root preinstall cannot update registry credentials for the active npm install
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 10.1k
- Forks
- 4.7k
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 19
Description
Is there an existing issue for this?
- I have searched the existing issues
This issue exists in the latest npm version
- I am using the latest npm
This is not just a request to bump a dependency for a CVE
- This is not solely a request to bump a dependency for a CVE
Current Behavior
With npm 12, a root preinstall script runs before npm fetches project dependencies. However, npm loads the user and project .npmrc files before running that script and does not use credential changes made by the script for the active installation.
npm/cli#2660 was a long-running request to execute root preinstall before dependency installation. A major use case raised repeatedly in that discussion was automatic authentication for private registries, including registries that issue short-lived tokens. npm 12 now provides the requested lifecycle ordering, but that use case remains impossible within a single npm install: the earlier configuration load means credentials created or refreshed by preinstall are not used by the dependency requests that follow it.
This can be reproduced when the project depends on a package in a private registry and preinstall creates or refreshes the registry credentials:
- npm starts with a missing, expired, revoked, or deliberately invalid credential.
- The root
preinstallscript successfully obtains a valid credential and writes it to the user.npmrc. - The same
npm installstill requests the private package using the configuration loaded beforepreinstalland fails withE401. - Running
npm installagain succeeds because the new npm process loads the credential written by the first invocation.
The first invocation therefore fails even though authentication completed successfully before the private-registry request. This particularly affects private registries that use short-lived tokens and authentication helpers intended to refresh them automatically.
Expected Behavior
After the root preinstall hook completes, npm should reload the configuration or credentials used for subsequent dependency requests. A valid registry credential written by preinstall should be used by the active npm install, allowing the first invocation to succeed.
If reloading configuration after preinstall is intentionally unsupported, the npm 12 lifecycle documentation should make that limitation explicit. Running root preinstall before dependency installation otherwise appears to support authentication and configuration preparation, while the active installation silently retains its earlier state.
Steps To Reproduce
The following generic reproduction works with any private npm registry and avoids committing a real token. Back up any credentials before adapting it.
-
Create a project containing a dependency from a private registry:
{ "name": "npm-preinstall-auth-repro", "version": "1.0.0", "private": true, "scripts": { "preinstall": "node refresh-auth.cjs" }, "dependencies": { "@private/example": "1.0.0" } } -
Add the registry to the project
.npmrc, replacing the example URL and scope:@private:registry=https://private-registry.example.test/npm/ -
Save working credentials in an untracked file named
valid-user.npmrc://private-registry.example.test/npm/:_authToken=VALID_TOKEN -
Create
refresh-auth.cjs. It replaces the user configuration during rootpreinstall:const { copyFileSync } = require("node:fs"); const { join } = require("node:path"); const { homedir } = require("node:os"); const target = process.env.npm_config_userconfig || process.env.NPM_CONFIG_USERCONFIG || join(homedir(), ".npmrc"); copyFileSync("valid-user.npmrc", target); console.log(`Wrote valid registry credentials to ${target}`); -
Point npm at a disposable user configuration containing an invalid token. In PowerShell:
$env:NPM_CONFIG_USERCONFIG = "$PWD/repro-user.npmrc" Set-Content -LiteralPath $env:NPM_CONFIG_USERCONFIG -Value '//private-registry.example.test/npm/:_authToken=INVALID_TOKEN' -
Run the installation with lifecycle and request output visible:
npm install --foreground-scripts --loglevel verbose -
Observe that
refresh-auth.cjsreports that it wrote the valid credential, but the subsequent private-registry request receives401 Unauthorizedand npm exits withE401. -
Run the same command again without changing any files:
npm install --foreground-scripts --loglevel verbose -
Observe that the second invocation succeeds because it loads
repro-user.npmrcafter the first invocation replaced its invalid credential.
The missing-credential variant behaves the same way: begin with a user configuration containing no registry credential, let preinstall add it, and observe that only the second npm invocation uses it.
Environment
The private registry hostname, username, and filesystem paths below are sanitized. No token value is included.
-
npm:
12.0.2 -
Node.js:
v24.18.1 -
OS Name:
Microsoft Windows 11 Enterprise 10.0.26200, 64-bit -
System Model Name:
Dell Pro Max 16 MC16250 -
npm config:
; "user" config from C:\Users\<user>\.npmrc //private-registry.example.test/npm/:_password = (protected) //private-registry.example.test/npm/:email = (protected) //private-registry.example.test/npm/:username = (protected) ; "env" config from environment cache = "Z:\\packages\\npm" ; node bin location = C:\nvm4w\nodejs\node.exe ; node version = v24.18.1 ; npm local prefix = <project-path> ; npm version = 12.0.2 ; cwd = <project-path> ; HOME = C:\Users\<user> ; Run `npm config ls -l` to show all defaults.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with npm install's configuration loading and root preinstall lifecycle entry points, then reproduce the issue with the provided private-registry setup and verbose logging. Trace when the user and project .npmrc files are read relative to preinstall; done means the active install uses credentials written by preinstall, or the lifecycle documentation clearly states that it does not.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 54/100