actions/setup-node registry-url interferes with OIDC trigger — example workflow fails with ENEEDAUTH when no NODE_AUTH_TOKEN
Nobody has claimed this yet.
- Dominant language
- MDX
- Stars
- 711
- Forks
- 4.2k
- Avg merge
- 4d 16h
- Merged PRs (30d)
- 3
Description
Summary
Following the official GitHub Actions example in Trusted publishing for npm packages verbatim — without a NODE_AUTH_TOKEN secret — npm CLI never triggers the OIDC flow and instead fails with one of:
npm error code ENEEDAUTH(the.npmrchas no usable token)npm error 404(when an empty_authTokenis sent and the registry rejects)
Even though every documented prerequisite is met:
id-token: writepermission ✅- npm CLI 11.5.1+ ✅ (verified 11.14.1)
ACTIONS_ID_TOKEN_REQUEST_URL/ACTIONS_ID_TOKEN_REQUEST_TOKENset ✅- Trusted Publisher configured on the package (
@sofereditor/corein our case) ✅
Root cause
actions/setup-node@v4 with registry-url: 'https://registry.npmjs.org' writes the following to the runner's ~/.npmrc (actually $RUNNER_TEMP/.npmrc via NPM_CONFIG_USERCONFIG):
//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
registry=https://registry.npmjs.org/
always-auth=false
The literal ${NODE_AUTH_TOKEN} placeholder is expanded by npm CLI at publish time from the environment. When no NPM_TOKEN secret is configured (the intended state for Trusted Publishers), NODE_AUTH_TOKEN is unset and the substitution becomes an empty string. npm CLI sees the _authToken= line as "auth is configured" and does NOT initiate the OIDC token exchange, instead attempting a classic publish with empty credentials → ENEEDAUTH or E404.
Reproduction
name: Publish
on: workflow_dispatch
permissions:
id-token: write
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- run: npm install -g npm@latest --force # ensure 11.5.1+
- run: npm publish --access public --provenance
With Trusted Publisher correctly set up for the package on npmjs.com and no NPM_TOKEN secret, the publish fails — exactly as the docs would suggest it should succeed.
Workaround that worked
Remove the _authToken line from .npmrc after setup-node runs:
- name: Strip _authToken from npmrc (let OIDC kick in)
run: |
npmrc="${NPM_CONFIG_USERCONFIG:-$HOME/.npmrc}"
sed -i '/_authToken/d' "$npmrc"
After this, npm CLI sees no auth in .npmrc, detects ACTIONS_ID_TOKEN_REQUEST_* env vars, calls https://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/<pkg> and publishes successfully with provenance.
Verified end-to-end: @sofereditor/{core,react,collab,export-pdf,export-docx,import-docx}@0.2.0 published via this workflow.
Suggested doc improvements
Two complementary changes (PR follows):
-
Update the GitHub Actions example workflow to either:
- Drop
registry-urland write.npmrcmanually with only the registry line, OR - Add the
_authToken-stripping step shown above with a one-line comment explaining why.
- Drop
-
Extend Troubleshooting to call out the most common failure mode for users following the example unchanged:
If you see
ENEEDAUTHorE404even though Trusted Publisher is configured andid-token: writeis granted, check$RUNNER_TEMP/.npmrc(or~/.npmrc) for a//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}line written byactions/setup-node. WhenNODE_AUTH_TOKENis unset (the expected state for Trusted Publishers without classic tokens), the placeholder expands to empty and npm CLI tries classic auth instead of OIDC. Either remove that line beforenpm publishor avoidsetup-node'sregistry-urloption.
I'm happy to open a PR with both changes.
Suggested diff for the .mdx
--- a/content/packages-and-modules/securing-your-code/trusted-publishers.mdx
+++ b/content/packages-and-modules/securing-your-code/trusted-publishers.mdx
@@ ... GitHub Actions example
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false # never use caching in release builds
+ # `setup-node` with `registry-url` writes an `_authToken` line in
+ # `.npmrc` that expands to empty when `NODE_AUTH_TOKEN` is unset.
+ # Empty auth tokens prevent npm CLI from initiating OIDC. Strip
+ # the line so the OIDC flow kicks in.
+ - name: Strip empty _authToken from .npmrc
+ run: |
+ npmrc="${NPM_CONFIG_USERCONFIG:-$HOME/.npmrc}"
+ sed -i '/_authToken/d' "$npmrc"
- run: npm ci
- run: npm run build --if-present
- run: npm test
- run: npm publish
@@ ... Troubleshooting
If you encounter an "Unable to authenticate" (ENEEDAUTH) error when publishing, first verify that the workflow filename matches exactly what you configured on [npmjs.com](https://npmjs.com), including the `.yml` extension. ...
+
+If `ENEEDAUTH` or `E404` persist after you've verified the trusted publisher
+configuration, check the generated `.npmrc`. `actions/setup-node` with
+`registry-url` writes a `//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}`
+line; without a `NODE_AUTH_TOKEN` secret the placeholder expands to empty
+and npm CLI treats that as "auth configured", short-circuiting the OIDC
+exchange. Either remove that line before `npm publish` or skip
+`registry-url` and configure the registry manually.
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
Update content/packages-and-modules/securing-your-code/trusted-publishers.mdx, starting with the GitHub Actions example and its Troubleshooting section. Incorporate the documented setup-node and empty _authToken behavior, then verify that the example and troubleshooting guidance cover the no-NODE_AUTH_TOKEN OIDC case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, node.js
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100