-
Couldn't load subscription status.
- Fork 7.3k
gh auth login #1445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh auth login #1445
Conversation
cd8edcf to
9cbcab2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's great that we're finally going to have this command 🎉
| { | ||
| name: "hostname set", | ||
| opts: &LoginOptions{ | ||
| Hostname: "rebecca.chambers", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
☣️
| fmt.Fprintln(opts.IO.ErrOut) | ||
| fmt.Fprintln(opts.IO.ErrOut, heredoc.Doc(` | ||
| Tip: you can generate a Personal Access Token here https://github.com/settings/tokens | ||
| The minimum required scopes are 'repo' and 'read:org'.`)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, but I'd be fine with printing information like this to stdout since it's part of the essential output of the login command. I do not expect that people will be redirecting stdout of login to a script or anyting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm torn; on the one hand, printing to STDOUT is absolutely fine here (and survey is using STDOUT). On the other, we print this kind of stuff to STDERR in other commands and I'd like to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other, we print this kind of stuff to STDERR in other commands and I'd like to be consistent.
True. But the way I see it, the only reason we separate out "special" notices from regular output is because we expect that the user might be piping regular output to a file or a script. If the user is not doing that (for this command, they are not likely to), there is no incentive for us to print notices on a separate stream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some software writes to the tty in raw mode for these types of informational notices, so the text is neither in stdout nor stderr.
Yes, I think device flow should absolutely be a follow-up. The device flow can be feature-detected and fits under the "Login with a web browser” flow as far as the user is concerned, so its implementation will not require almost any UI tweaks.
Uh, I declared bankruptcy on testing the browser auth flow since I did not have any ideas how to stub it back then. If you do, that would be awesome! Especially because after this, I would really like us to opensource the
I think that's good enough, especially since we might be tweaking the flow still. Credentials being correctly saved is most of what matters |
|
note to self: do some bolding / green check / formatting on browser flow prompts |
f33828f to
d1d310d
Compare
|
I've...
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything looks great; thank you!
The only potential blocker from my standpoint is GITHUB_TOKEN handling. As it stands, this branch only respects configuration from ~/.config/gh/hosts.yml file, but if a user supplied an invalid or revoked GITHUB_TOKEN via their environment, any attempt of a gh command will fail with a HTTP 401, but gh auth login will show “You're already logged into github.com as mislav. Do you want to re-authenticate?” And even if I went through re-authentication process, a new token will be written to my config file, but the old (broken) GITHUB_TOKEN from environment still takes precedence and sabotages my gh operations.
| defer opts.IO.In.Close() | ||
| token, err := ioutil.ReadAll(opts.IO.In) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, but I think the logic to actually read the token from stdin might belong in loginRun instead of here. Typically, we used RunE so far to just to argument/flags processing, but avoided executing any command logic. I'm on the fence about this, so I could go either way. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was very unsure. I think this falls under the category of argument parsing if you consider the value on STDIN to be an argument. I felt that the "inputs" of this command were a hostname and a token and that loginRun should only care about those two things and be less concerned with whence they came. I decided to see how uncomfortable the testing felt and that turned out to feel fine so I'm content to leave it like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That reasoning makes sense!
| fmt.Fprintln(opts.IO.ErrOut) | ||
| fmt.Fprintln(opts.IO.ErrOut, heredoc.Doc(` | ||
| Tip: you can generate a Personal Access Token here https://github.com/settings/tokens | ||
| The minimum required scopes are 'repo' and 'read:org'.`)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other, we print this kind of stuff to STDERR in other commands and I'd like to be consistent.
True. But the way I see it, the only reason we separate out "special" notices from regular output is because we expect that the user might be piping regular output to a file or a script. If the user is not doing that (for this command, they are not likely to), there is no incentive for us to print notices on a separate stream.
|
This is an excellent improvement. Thanks! Also, the wee screencasts let me see the entire scope of what you are trying to do in seconds. Great. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a minor point about GITHUB_TOKEN handling, but would be also fine if we addressed various authentication issues and error messaging around GITHUB_TOKEN in a follow-up. 🌟
| return nil | ||
| } | ||
|
|
||
| var clientFromCfg = func(hostname string, cfg config.Config) (*api.Client, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why this and validateHostCfg are overridable functions (i.e. assigned to a var)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clientFromCfg is overriden in tests; validateHostCfg is not and that's just vestigial, I'll fix that.
|
|
||
| // Returns whether or not scopes are present, appID, and error | ||
| func (c Client) HasScopes(wantedScopes ...string) (bool, string, error) { | ||
| url := "https://api.github.com/user" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's great that this no longer depends on the /user endpoint!
| } | ||
|
|
||
| return false, appID, nil | ||
| if !search["read:org"] && !search["admin:org"] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the simplicity of this new implementation for checking scopes 🏅
|
|
||
| opts.Token = strings.TrimSpace(string(token)) | ||
| } else if ghToken != "" { | ||
| opts.Token = ghToken |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that making GITHUB_TOKEN here indistinguishable from the one passed via --with-token is not the behavior that I would expect. That could result in GITHUB_TOKEN being stored to hosts.yml, which I don't think should ever happen since GITHUB_TOKEN is environment-only.
It's useful to think of GITHUB_TOKEN as credentials stored in a virtual layer "above" (and entirely separate of) hosts.yml. So I think that gh auth login/status should be aware of GITHUB_TOKEN being set and help you determine whether the credentials are valid, but they can't help you interactively refresh the credentials since only the user can change an environment variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That could result in GITHUB_TOKEN being stored to hosts.yml, which I don't think should ever happen since GITHUB_TOKEN is environment-only.
I was going quickly and didn't even think about this 🤦♀️ I will at least push a commit to not save the config if GITHUB_TOKEN is being validated.
| return errors.New("empty hostname would leak oauth_token") | ||
| } | ||
|
|
||
| err := cfg.Set(opts.Hostname, "oauth_token", opts.Token) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only stores oauth_token key for a host and not the user key, but maybe that's fine since we don't really need the user key for anything other than reassurance for people manually inspecting their config file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, that's a good point though; I might as well set that.
Merge pull request cli#1445 from cli/auth-cmd
|
@vilmibm Curious if we need a URL validation on this as it accepts jibberish and even a blank The app hangs as the browser just goes to a dead page as expected. Happy to open an issue if needed. |
This PR adds
gh auth login.interactive mode - paste token
interactive mode - browser flow
non-interactive mode
Part of #1413
Open questions: