[FEATURE] Standardised Browser-based Login Mechanism #93
Replies: 28 comments
-
Looping in @juanpicado for Verdaccio, @zkochan for pnpm, and maybe @Phanatic for the GitHub package registry. My personal opinion is that browser-based authentication is a great feature, and I'd love to find a way to implement it (if we can avoid having to rely on reverse engineering!) 🙂 |
Beta Was this translation helpful? Give feedback.
-
I was hit by this as well. |
Beta Was this translation helpful? Give feedback.
-
Would love to see this, is it the lack of a PR with a more detailed technical write up why we didn't talk about it on the last RFC call? Or just an oversight? |
Beta Was this translation helpful? Give feedback.
-
I didn't realise I needed to do a PR, as I was just told to open an issue. The behaviour described in this ticket is already practically implemented in npm; it just lacks standardisation, which means other tools won't implement it. Since this functionality is currently only in npm Enterprise, the idea is to take the custom flow npm has implemented & morph/switch it into being the OAuth Device Code Grant Flow, which does have a standard backing it. I don't expect the public registry to support this flow any time soon; it's more that we have a standard so that clients can interop and private registries can be secured better, paving the path for the public registry to switch to this. If desired, I can write up a PR, but there's really not much more to say other than what I've said here. It requires a small change to npm CLIs codebase, a change to npmE's auth, and documentation in the registry API docs. There's not more technical stuff to write because it's literally "implement this other standard from the IETF" |
Beta Was this translation helpful? Give feedback.
-
To be clear, I am not sure you do, I just was wondering why this didn’t make it on the schedule for last meeting. Its an awesome idea and I want to see it move forward. |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Re the question as to why we didn't discuss at the open call, it's simply a matter of prioritizing the issues that we're currently working on and are relevant to getting npm v7 out the door. This isn't forgotten! But it might take a while to get to, especially since it involves more folks who manage the registry back-end and auth systems. The CLI work required is relatively minor. In any event, we may still want to enable WebAuth for the public registry at some point. If the only obstacle to other registries and clients implementing that is that it's not adequately documented, well, we can certainly just document it. |
Beta Was this translation helpful? Give feedback.
-
This was shared by @wesleytodd on the RFC meeting call: https://tools.ietf.org/html/draft-ietf-oauth-browser-based-apps-00 |
Beta Was this translation helpful? Give feedback.
-
@gcallaghan sent me that, so maybe he can share how that would be helpful here. |
Beta Was this translation helpful? Give feedback.
-
I'm not fully versed in the implementation of NPM cli authentication mechanisms, however, the discussion shares a similar constraint as mobile and single page applications where the client cannot protect a secret. In this case, the Proof of Key Code Exchange (PKCE) flow adds a step with a cryptographic challenge. This automatic handshake can take the place of the user entering the device code, resulting in a nicer end user experience. Additionally, most of the steps can be handled via integrating the AppAuthJS helper library today. This spec would work with most OpenID Connect compliant Identity Providers and could be programmatically verified by inspecting their |
Beta Was this translation helpful? Give feedback.
-
Yes, this URL is entirely under our control. So, open to suggestions; it just has to have the same API as listed in the spec; POST request with body.
I believe that's correct. We could of course always have the client construct a URL that uses the device_code in it; I think maybe the PKCE stuff may help here, but I'd definitely have to read more into device_code vs PKCE or whether they're complimentary.
To my knowledge, client_code is just random, and isn't actually verified on the server, other than client_code and device_code must match as a pair to retrieve the access token
Can't hurt to have this as an option, may improve security; though refresh tokens aren't explicitly required to be implemented in OAuth |
Beta Was this translation helpful? Give feedback.
-
@gcallaghan I'm pretty sure we'd have to reimplement AppAuthJS, as it likely doesn't work from CLIs; however, if memory serves, PKCE is just "generate an addittional code, hash it, send the hash to the server; then when getting the response, verify the hash matches or something. They seem to be solving similar but different problems. I've posted a tweet to gain clarification: https://twitter.com/thisismissem/status/1230771716277669890?s=21 |
Beta Was this translation helpful? Give feedback.
-
(Sorry about that, my browser had text in the comment box and I've been using gitlab way too much which has a cancel button) |
Beta Was this translation helpful? Give feedback.
-
This was the best way I could explain PKCE https://apisyouwonthate.com/blog/pkce-vs-proxy. That is still in context of classically web based services. One of the key requirements is that you can rely on a human browser based interaction and that redirect URI. The result of that successful transaction could be almost any form of credential; mTLS cert, opaque API key, JWT. The cli can then pick that up off disk from a well known location (awscli uses ~/.aws/credential) and decorate network requests with an Authorization Bearer or configure the http client to use the client certificates etc. A good end result but hacky implementation(creative work arounds for Google constraints) example is https://github.com/cevoaustralia/aws-google-auth where the code jumps through hoops to fill out Google's login form from the CLI and you get temporary AWS STS credentials at the end. |
Beta Was this translation helpful? Give feedback.
-
Here's a series of really good write ups on device code grant flow from Okta: https://www.oauth.com/oauth2-servers/device-flow/ |
Beta Was this translation helpful? Give feedback.
-
specifically, reading more, it would seem as device code grant flow does not involve a client_secret, then the need for PKCE is not present. |
Beta Was this translation helpful? Give feedback.
-
@ThisIsMissEm right you would do one or the other (PKCE or Device Code) depending on what authentication experience you want to achieve. |
Beta Was this translation helpful? Give feedback.
-
Right, so, in the end; I don't think PKCE is what we're after, and we are actually after Device Code flow — we want users to be taken from the CLI to their browser to log-in unless they have an active access token or refresh token |
Beta Was this translation helpful? Give feedback.
-
Except that ...
via the Okta link you sent. I know personally, when I use npm I am at a computer with a browser and keyboard. With those constraints, PKCE would seem more appropriate and accomplish the flow you describe without the extra user input step. There will probably(hopefully) already be the additional step of MFA when integrating with an Enterprise SSO. Removing a step helps reduce user friction. |
Beta Was this translation helpful? Give feedback.
-
It all depends on what you scope the "device" to; if you think physical machine, then yeah, you'd be right. But if you think of the terminal as a non-browser device, then device code grant flow makes sense. Sure, you could also do PKCE for a terminal, but to even start that flow you'd need to open a browser, hence just going with device code grant flow which is explicit around polling for an access token. I would see no reason why the registry may not have it's own TOPT on top of the SSO's.
|
Beta Was this translation helpful? Give feedback.
-
That's a perfectly reasonable model for the CLI (and probably perfect when considering headless docker containers and build machines) and there is certainly no technical reason why the registry couldn't have its own TOPT. From a technical and security perspective Device Code flow has all the functionality you want and will get the job done, no question. It's a good choice. From my personal perspective supporting authentication systems, reducing steps for users can decrease their frustration and, as a result, support tickets while still maintaining the level of security you want. Additionally, extra steps tend to drive users to turn off security, resulting in a weaker overall posture. I've had success building and supporting tooling leveraging PKCE with CLI's to support a smoother developer experience. It's also not strictly a boolean option, really more of a prioritization and order of work. One doesn't mean you can't do the other. If the process abides by the spec, it is dynamic and part of the negotiation at runtime. It's an operational and DX consideration which are not always thought about with security controls. This often gives security a bad rep. It's the only reason I'm advocating so strongly for this as a consideration. Both are 100% appropriate and viable IMHO. (I'd argue strongly against a custom protocol) |
Beta Was this translation helpful? Give feedback.
-
I must say I'm not entirely sure how PKCE would work nicely for CLIs, because eventually you need to be taken to the browser to sign in, and then the CLI has no way to know once that's complete, unless it runs a localhost server to receive the OAuth callback. Past localhost servers run by tools, especially to connect remote services to local ones, have been proven reasonably insecure (thinking Zoom, Norton AV, etc), so this I think makes Device Code Grant Flow preferable for CLIs; the spec also doesn't say we cannot place the user token in the URL that is opened in the browser, afaik. I'm definitely for using an existing standard, over creating our own standard, but either way, I'd like this browser based flow to supersede basic auth for interactive users |
Beta Was this translation helpful? Give feedback.
-
the heroku cli login experience is pretty smooth for a flow like this. it doesn't bring focus back to the terminal, but is able to complete the flow after logging in through the browser without needing to manually transfer a code. |
Beta Was this translation helpful? Give feedback.
-
Given the recent news, maybe there's a great opportunity here to reuse the browser-based GitHub SSO infrastructure to "Connect via Github" on the client CLIs (cc @ethomson) (Quick summary of the thread: we're trying to improve the safety of Yarn's and npm's users by implementing a browser-based login mechanism where passwords aren't required) |
Beta Was this translation helpful? Give feedback.
-
Just a heads up, I thought I wasn't going to have time to work on this for a little while, but now I'll be able to start implementing this on Monday. (TL;DR; I parted ways with the company I was working for, and I've now a lot of paid leave) @travi I just found a neat hack that can shift focus back to the terminal on os x: redirect to |
Beta Was this translation helpful? Give feedback.
-
@arcanis @ethomson yes! exactly! The idea is that any oAuth server that implements the device code grant flow should be able to be used as the authenticating server; originally I was needing this for a private verdaccio install at the company I was working for, as setting up gitlab for authenticating npm against verdaccio was a PITA. |
Beta Was this translation helpful? Give feedback.
-
Unfortunately, I've not been able to take this further than this discussion at the moment, as I can't exactly spend unpaid time on open-source whilst freelancing and starting a company. |
Beta Was this translation helpful? Give feedback.
-
How did the specification of auth-type=web come to be in the end? In my company, using a verdaccio with custom authentication. What should we refer to when implementing an authentication system with auth-type=web? |
Beta Was this translation helpful? Give feedback.
-
What / Why
Originally the npm CLI supported logging into the registry purely via using Basic Authentication headers on requests; when npm Enterprise launched, it added a new login mechanism which is known in the code as WebAuth, which launches the users' browser of choice at a given URL in order to authenticate in-browser, allowing for usage of SSO and SAML login services, as well as other security mechanisms around logins, which would be difficult to support purely through the CLI.
Outside of npm, there are third-party registries such as Verdaccio and Nexus 3; These registries can be configured to integrate with SSO services, such as Google and Gitlab. However, this only really applies for their web interface, for the CLI, you need to generate a fixed application-specific token and then use that.
I raised an issue with Verdaccio, asking if they'd want to implement WebAuth that could make the SSO sign-in user journey much easier and remove a lot of confusion, errors and frustration with onboarding users to a private registry using SSO; They refused, as WebAuth isn't based on a standard, and it'd just be a reverse engineer of something internal to npm.
This is a very valid point, and this now leads us to this RFC / FEATURE request: Standardised browser-based login mechanism.
Proposal
The idea is to implement the OAuth 2.0 Device Code Grant Flow or create a standard derived from it. I'm not advocating that the registry implement the full OAuth 2.0 protocol specification, just this specific feature.
You can read a more human-understandable version of the flow here:
The overall difference between WebAuth and the OAuth 2.0 Device Code Grant Flow isn't particularly significant, as far as I can tell.
Request Flow
/token
. This request looks like the following:verification_uri
— this URI may also include theuser_code
, rather than requiring the user to manually enter the code. In the background, the CLI starts polling the following request at the giveninterval
:Implementation Required:
This would require implementation work in:
Closing Note:
I would be willing to write an implementation of the CLI flow of making the initialization request, then opening the browser, and polling in the background whilst the login takes place. From my recollection of OAuth 2.0, we don't have to implement expiration of the
access_token
, meaning not having anexpires_in
orrefresh_token
, however, I'd likely encourage it, though this does make interacting with the registry potentially more complicated.This proposal does not replace being able to issue a token for use from CI or other automation. The intent is only to replace entering in your username, email, password, and 2FA code when logging in. It also does not affect the usage of 2FA for publishes or reads — that is, a registry may require additional authentication at a later date once you've logged in.
Beta Was this translation helpful? Give feedback.
All reactions