npm Community Forum (Archive)

The npm community forum has been discontinued.

To discuss usage of npm, visit the GitHub Support Community.

Cannot set npm config keys containing underscores (registry auth tokens, for example) via npm_config_ environment variables

The issue is essentially a copy of Issue #15565 (which I can’t link because I’m a new user), where someone suggested I post my analysis here.

What I Wanted to Do

I want to set the environment variable npm_config_//registry.npmjs.org/:_authToken and have npm pick it up as the authentication token for that npm registry.
Example:

env 'npm_config_//registry.npmjs.org/:_authToken=00000000-0000-0000-0000-000000000000' npm publish .

What Happened Instead

npm failed with ENEEDAUTH

Reproduction Steps

env 'npm_config_//registry.npmjs.org/:_authToken=00000000-0000-0000-0000-000000000000' npm publish .

Again, see #15565 for more on reproduction.

Details

Versions:

{ npm: '6.1.0',
  ares: '1.14.0',
  cldr: '33.0',
  http_parser: '2.8.0',
  icu: '61.1',
  modules: '64',
  napi: '3',
  nghttp2: '1.29.0',
  node: '10.4.0',
  openssl: '1.1.0h',
  tz: '2018c',
  unicode: '10.0',
  uv: '1.20.3',
  v8: '6.7.288.43-node.7',
  zlib: '1.2.11' }

I believe the cause for this is the way npm translates environment variables to config keys.

When we have an environment variable npm_config_//registry.npmjs.org/:_authToken,
config reads it from the environment and replaces every _ character with a - character, so the config key would be //registry.npmjs.org/:-authToken,
but then when npm tries to find the token, it looks for a config key for the registry that ends in :_authToken, which fails because the underscore was translated.

So at its root there are two parts of the code that disagree on how config keys should be normalised, and it seems to affect all config keys containing underscores (i.e. none of those can be set using an environment variable).
To fix this I would start by extracting a function that performs this normalisation, and then maybe modify config’s get to normalise all keys prior to lookup.

I hope this can get someone started on a fix?
I’ll happily try to provide one but would need guidance.


As you note, this is not supported. The usual way to pass in auth tokens via the enviornment is, to add the following to your .npmrc:

//registry.npmjs.org/:_authToken=${AUTH_TOKEN}

And then run:

env 'AUTH_TOKEN=00000000-0000-0000-0000-000000000000' npm publish

Does this meet your needs?


It does not, since that causes every npm command to fail with

Error: Failed to replace env in config: ${AUTH_TOKEN}

as long as that variable is unset; see also https://github.com/npm/npm/issues/15565 and https://github.com/npm/npm/issues/8356.

I’d rather be able to help support using the npm_config_… variable. :slight_smile:


Yes, that’s certainly true, if used it has to be set.

Historically the fact that auth keys were impossible to round-trip through the environment was considered a feature. That said, I don’t see a justification for that any more.

I would suggest anyone looking to implement this should look at changing the config loader. A change for this should be targeted, perhaps making it so that underscores aren’t translated to hyphens after colons, or something similar.


Thanks for the hint, I’ll give it a shot!

I kept thinking about something along the lines of treating underscores and hyphens identically everywhere, but this more defensive seems like a better idea. :ok_hand:


(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)


I started to use this feature and ran into issues with AWS CodeBuild rejecting the environment variable name.

This is not npm’s fault, obviously. And I can work around this by setting the environment variable npm needs from another environment variable which I define in CodeBuild (e.g. NPM_AUTH_TOKEN):

env "npm_config_//registry.npmjs.org/:_authtoken=${NPM_AUTH_TOKEN}" npm whoami

Now, this kinda defeats the purpose of the initial idea.

What if I could provide a simpler environment variable directly which npm would pick up, e.g. npm_config_authtoken, this could be read in getCredentialsByURI() and if present used.


I mean, use it sparingly, but technically the latest npm clients should be able to recognize token= and _authToken= without the registry nerf dart prefix. Though I think that only works for installs right now.


Ok, I will check if it works for install and publish as well.

Which one is more likely to be kept supported in the future? token or _authToken?


Nope, does not work with publish.


I have the same problem with npm 6.9.0. I modified npm/node_modules/node-fetch-npm/src/index.js to log headers being sent. The Authorization header does not show up.

env 'npm_config_//registry.npmjs.org/:_authToken=foo' /usr/local/bin/npm whoami
Headers [HeadersPrototype] {
  [Symbol(map)]:
   [Object: null prototype] {
     connection: [ 'keep-alive' ],
     'user-agent': [ 'npm/6.9.0 node/v10.15.3 darwin x64' ],
     'npm-in-ci': [ 'false' ],
     'npm-scope': [ '' ],
     'npm-session': [ 'd2bf82408d854171' ],
     referer: [ 'whoami' ] } }
env 'npm_config_//registry.npmjs.org/:_authToken=foo' /usr/local/bin/npm i lodash
Headers [HeadersPrototype] {
  [Symbol(map)]:
   [Object: null prototype] {
     connection: [ 'keep-alive' ],
     'user-agent': [ 'npm/6.9.0 node/v10.15.3 darwin x64' ],
     'npm-in-ci': [ 'false' ],
     'npm-scope': [ '' ],
     'npm-session': [ '7920b3956e1c488c' ],
     referer: [ 'install lodash' ],
     'pacote-req-type': [ 'packument' ],
     'pacote-pkg-id': [ 'registry:lodash' ],
     accept:
      [ 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' ],
     'if-none-match': [ '"0e3e7a18527dba65d50b3e2a49b3813c"' ],
     'if-modified-since': [ 'Tue, 07 May 2019 15:25:46 GMT' ] } }

But npm config ls shows the -authToken config being picked up from the env vars.

; environment configs
//registry.npmjs.org/:-authtoken = "foo"