diff --git a/__tests__/authutil.test.ts b/__tests__/authutil.test.ts index d5f6c195f..b39c07a1d 100644 --- a/__tests__/authutil.test.ts +++ b/__tests__/authutil.test.ts @@ -118,6 +118,24 @@ describe('authutil tests', () => { expect(process.env.NODE_AUTH_TOKEN).toEqual('foobar'); }); + it('should not export NODE_AUTH_TOKEN if not set (OIDC support)', async () => { + // Clean NODE_AUTH_TOKEN from environment + delete process.env.NODE_AUTH_TOKEN; + await auth.configAuthentication('https://registry.npmjs.org/'); + expect(fs.statSync(rcFile)).toBeDefined(); + // NODE_AUTH_TOKEN should not be exported to environment if not initially set + // This allows OIDC authentication to work properly + const rc = readRcFile(rcFile); + expect(rc['registry']).toBe('https://registry.npmjs.org/'); + }); + + it('should export empty string NODE_AUTH_TOKEN if explicitly set to empty (OIDC support)', async () => { + process.env.NODE_AUTH_TOKEN = ''; + await auth.configAuthentication('https://registry.npmjs.org/'); + expect(fs.statSync(rcFile)).toBeDefined(); + expect(process.env.NODE_AUTH_TOKEN).toEqual(''); + }); + it('configAuthentication should overwrite non-scoped with non-scoped', async () => { fs.writeFileSync(rcFile, 'registry=NNN'); await auth.configAuthentication('https://registry.npmjs.org/'); diff --git a/dist/setup/index.js b/dist/setup/index.js index c59bedb4f..b39ea9a1b 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -53633,8 +53633,12 @@ function writeRegistryToFile(registryUrl, fileLocation) { newContents += `${authString}${os.EOL}${registryString}`; fs.writeFileSync(fileLocation, newContents); core.exportVariable('NPM_CONFIG_USERCONFIG', fileLocation); - // Export empty node_auth_token if didn't exist so npm doesn't complain about not being able to find it - core.exportVariable('NODE_AUTH_TOKEN', process.env.NODE_AUTH_TOKEN || 'XXXXX-XXXXX-XXXXX-XXXXX'); + // Only export NODE_AUTH_TOKEN if explicitly provided by user + // This is required to support NPM OIDC tokens which need NODE_AUTH_TOKEN to be unset + // See: https://github.com/actions/setup-node/issues/1440 + if (Object.prototype.hasOwnProperty.call(process.env, 'NODE_AUTH_TOKEN')) { + core.exportVariable('NODE_AUTH_TOKEN', process.env.NODE_AUTH_TOKEN); + } } diff --git a/package-lock.json b/package-lock.json index 97d9da250..47a5abe6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -513,6 +513,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", diff --git a/src/authutil.ts b/src/authutil.ts index e4b823bd5..f114ec1e9 100644 --- a/src/authutil.ts +++ b/src/authutil.ts @@ -46,9 +46,10 @@ function writeRegistryToFile(registryUrl: string, fileLocation: string) { newContents += `${authString}${os.EOL}${registryString}`; fs.writeFileSync(fileLocation, newContents); core.exportVariable('NPM_CONFIG_USERCONFIG', fileLocation); - // Export empty node_auth_token if didn't exist so npm doesn't complain about not being able to find it - core.exportVariable( - 'NODE_AUTH_TOKEN', - process.env.NODE_AUTH_TOKEN || 'XXXXX-XXXXX-XXXXX-XXXXX' - ); + // Only export NODE_AUTH_TOKEN if explicitly provided by user + // This is required to support NPM OIDC tokens which need NODE_AUTH_TOKEN to be unset + // See: https://github.com/actions/setup-node/issues/1440 + if (Object.prototype.hasOwnProperty.call(process.env, 'NODE_AUTH_TOKEN')) { + core.exportVariable('NODE_AUTH_TOKEN', process.env.NODE_AUTH_TOKEN); + } }