cli icon indicating copy to clipboard operation
cli copied to clipboard

Support npm login via token

Open jo opened this issue 10 years ago • 23 comments

we are using npm enterprise which authenticates against github. Here we are using a personal access token to deal with githubs 2fa.

The cli could ask if the user wants to login via username/password or via token.

https://github.com/npm/npm-registry-client#credentials

jo avatar Aug 19 '15 15:08 jo

better: check ~/.npmrc for presence of such token and use it:

@myscope:registry=https://npme.myregistry.org/
https://npme.myregistry.org/:_authToken=7fd78dea2be7f6dbd127e75fbb5cd49601f87fc9

jo avatar Aug 19 '15 20:08 jo

If you just enter your github username and password for npm it works automatically, at least that's what @gr2m told me. Good question what happens with 2FA then, though. But it should have a built solution for that.

boennemann avatar Aug 19 '15 20:08 boennemann

I received 2FA pin (via SMS) but cli aborts without asking for it.

jo avatar Aug 19 '15 20:08 jo

This is an example of how npm resolves the token per registry: https://github.com/npm/npm/blob/master/lib/whoami.js#L14

jo avatar Aug 19 '15 20:08 jo

The way that works for github atm is that they send back a special header indicating that the "one-time-password" is missing. See here: https://github.com/semantic-release/cli/blob/master/src/lib/github.js#L56 I suppose npm just sends the same header.

boennemann avatar Aug 19 '15 20:08 boennemann

For npm Enterprise its recommendet to store the token in ~/.npmrc: http://blog.npmjs.org/post/106559223730/npm-enterprise-with-github-2fa

That way we could just get it from there and would be fine.

jo avatar Aug 19 '15 20:08 jo

Yes you're totally right :) We're using npmconf to load npm config anyways, so this should be a simple addition. https://github.com/semantic-release/cli/blob/master/src/index.js#L59

boennemann avatar Aug 19 '15 21:08 boennemann

But, I'm thinking, we're generating a github token already, why don't we just that one for both npme and travis? I liked the idea for generating a new token for every repo, because if you just take the one from the .npmrc and someone calls npm logout this token won't work any longer. That way you can break builds/deploys/publishes and it's very hard to debug that.

boennemann avatar Aug 19 '15 21:08 boennemann

Combining it with the findings of this issue: https://github.com/semantic-release/semantic-release/pull/53 this is how it would work:

If the pkg.name contains a scope we call conf.get('@'+scopeName+'/registry'). If that returns a registry we know this is npme, which means we don't ask for npm credentials any longer, we just upload the github token both as NPM_TOKEN and GH_TOKEN to Travis. How does that sound?

boennemann avatar Aug 19 '15 21:08 boennemann

I'm not totally sure that

If that returns a registry we know this is npme

is true.

jo avatar Aug 19 '15 21:08 jo

I'm pretty sure it is. Can you think of any case where this would return a non enterprise registry?

boennemann avatar Aug 19 '15 21:08 boennemann

No one prevents me from adding such an entry for npm Private Modules:

@jo:registry=https://registry.npmjs.org/

jo avatar Aug 19 '15 21:08 jo

Are you sure that

npm logout --registry https://npme.myregistry.org

invalidates the token? I just tried and got an 500 response:

Registry returned 500 for DELETE on https://npme.myregistry.org/-/user/token/7fd78dea2be7f6dbd127e75fbb5cd49601f87fc9

And after that

npm whoami --registry https://npme.myregistry.org

still returned my username, which means that it successfully made a request with that token.

Having that said I think we could do this:

  1. The user inputs the registry url (which defaults to the one in package.json's publishConfig)
  2. We lookup conf.get(registry + ':_authToken')
  3. If 2) returns a value, use that and skip username/password auth

jo avatar Aug 19 '15 21:08 jo

Okay I see, because it's actually just a GitHub token, npm doesn't do anything to the token on logout. I'm fine with your plan then :+1:

One caveat conf.get(registry + ':_authToken') should be conf.get(nerfDart(registry) + ':_authToken'), where nerf-dart is this module: https://github.com/npm/npm/blob/master/lib/config/nerf-dart.js

I'm already using it for semantic-release, and one other project, plus we're going to need it here, so I'll publish that as a standalone package. I'll post it once it's there so we can use it for this feature.

boennemann avatar Aug 20 '15 11:08 boennemann

Alright here you go for the nerf-darts: https://github.com/boennemann/nerf-dart

boennemann avatar Aug 20 '15 12:08 boennemann

@jo @boennemann what's the status here?

We currently have the issue with our NPM Enterprise setup where we'd like to use a dedicated machine user for the CI setup, and we'd also like to reuse one token instead of generating one all the time. Giving admin rights to the machine user to all repos on GitHub is not an option, so instead we want to create a token for only the rights that are needed and then use that token for the CI setup.

How would we solve that?

gr2m avatar Sep 23 '15 14:09 gr2m

I think thats a different use case now. I assume that the token we're using for the CI setup can be different from the one in our .npmrc. So the CLI needs to ask whether we use the token from npmrc or manually provide one. We could also enforce promting with a flag.

jo avatar Sep 23 '15 15:09 jo

I think this issue is not updated for the public npm registry 2fa setting. Should this be taken into account as well? If so, can that setting be read from npm.profile.get?

kbrandwijk avatar Jan 07 '18 06:01 kbrandwijk

I'm waiting for my other PR to be merged before submitting a PR with support for npm 2fa. I have it working locally, but I don't know if npme uses the same methodology. Any pointers on how I can test that?

kbrandwijk avatar Jan 07 '18 16:01 kbrandwijk

Regarding the npme + authentication token. I have read up on this, and it seems this should work:

  • Check for token in npm config (based on registry and package scope)
  • If present, use as NPM_TOKEN and GH_TOKEN
  • If not present, follow normal auth routine

Does that sound about right?

kbrandwijk avatar Jan 07 '18 18:01 kbrandwijk

I'm not familiar with npme authenticating against GitHub, so I can't tell if it would work, but I don't see why not.

Regarding reading the npm config in npmrc, you might find some useful stuff in the npm plugin:

  • https://github.com/semantic-release/npm/blob/master/lib/get-client-config.js
  • https://github.com/semantic-release/npm/blob/master/lib/get-registry.js
  • https://github.com/semantic-release/npm/blob/master/lib/get-last-release.js#L14

pvdlg avatar Jan 07 '18 20:01 pvdlg

Just wondering if it's correct to use that token as GH_TOKEN as well, because the authentication to npm(e) doesn't necessarily have to match the authentication used in the CI to publish releases to GH. Maybe an extra question before asking for GH credentials: 'Do you want to use the authentication token for Github authentication?' or something?

kbrandwijk avatar Jan 07 '18 20:01 kbrandwijk

After discussing with @pvdlg, will implement as described above:

  • If authToken found for (scoped) registry, ask for confirmation before asking GH credentials.

kbrandwijk avatar Jan 07 '18 22:01 kbrandwijk