npm .npmrc Auth Token in CI - Configure Registry Credentials Safely
By Kaveh Alemi·Latchkey
Private installs need an _authToken in .npmrc. In CI the token must come from a secret and the variable in .npmrc must actually expand, or npm sends the literal placeholder and auth fails.
What this error means
Private package installs fail with 401/403, or npm sends the unexpanded token placeholder verbatim because the .npmrc variable was never expanded by the shell or by npm config.
npm
npm ERR! code E401
npm ERR! 401 Unauthorized - GET https://registry.npmjs.org/@acme%2fui
npm ERR! authToken in .npmrc: ${NPM_TOKEN} (not expanded)
Diagnose it: which registry, and with what credentials?
Registry errors are resolved in a precedence chain, and the effective value is rarely the one in the file you are looking at. Scoped registries, .npmrc files at several levels, and environment variables all combine before a request is made.
Terminal
# the effective, fully merged configuration
npm config list -l | grep -E "registry|_auth|always-auth"
# where each value came from
npm config get registry
npm config get @yourscope:registry
# prove the token works, independently of the install
curl -sI -H "Authorization: Bearer $NPM_TOKEN" \
"$(npm config get registry)@yourscope%2fpackage" | head -1
Common causes
The token variable was not expanded
A committed .npmrc referencing an env-var token is only expanded when the value is written via the shell or npm config sees the env var; otherwise the literal placeholder string is sent.
No token secret is available in CI
The workflow never injects the token, so .npmrc has no usable credential.
How to fix it
Write the token from a secret at runtime
Expose the token as an env var from a secret.
Write the expanded value into .npmrc before install.
Keep the token in CI secrets, write or expand it into .npmrc at runtime, and add .npmrc token lines to .gitignore so a credential never lands in source control.
Frequently asked questions
What causes npm .npmrc auth token in CI?
There are 2 common causes: the token variable was not expanded and no token secret is available in ci. A committed .npmrc referencing an env-var token is only expanded when the value is written via the shell or npm config sees the env var; otherwise the literal placeholder string is sent.
How do I fix npm .npmrc auth token in CI?
There are 2 fixes depending on which cause you have: write the token from a secret at runtime and pass the secret through the env. Work through them in order, since the first is the most common.
What does npm .npmrc auth token in CI actually mean?
Private package installs fail with 401/403, or npm sends the unexpanded token placeholder verbatim because the .npmrc variable was never expanded by the shell or by npm config.
How do I stop npm .npmrc auth token in CI happening again?
Keep the token in CI secrets, write or expand it into .npmrc at runtime, and add .npmrc token lines to .gitignore so a credential never lands in source control.