Skip to content
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

login: improve text on already authenticated and on OAuth login #5774

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Benehiko
Copy link
Member

@Benehiko Benehiko commented Jan 27, 2025

Users have trouble understanding the different login paths on the CLI. The default login is performed through an OAuth flow with the option to fallback to a username and PAT login using the docker login -u <username> option.

This patch improves the text around docker login, indicating:

  1. The username is shown when already authenticated
  2. When not authenticated, the OAuth login flow explains the fallback clearly to the user and indicates a PAT can be used instead of a password.
  3. The password prompt now explicitly states that it accepts a PAT.

image
image

- What I did

- How I did it

- How to verify it

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@codecov-commenter
Copy link

codecov-commenter commented Jan 27, 2025

Codecov Report

Attention: Patch coverage is 35.29412% with 11 lines in your changes missing coverage. Please review.

Project coverage is 59.41%. Comparing base (41c2786) to head (2198ccc).
Report is 10 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5774      +/-   ##
==========================================
- Coverage   59.42%   59.41%   -0.02%     
==========================================
  Files         347      347              
  Lines       29402    29414      +12     
==========================================
+ Hits        17472    17476       +4     
- Misses      10958    10966       +8     
  Partials      972      972              

Copy link
Collaborator

@vvoland vvoland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Benehiko
Copy link
Member Author

I'll update the tests quick so we can get this in. I think we might also want to adjust the prompt slightly when using docker login -u <username so that it says "Password/PAT:" instead of just "Password:"

Users have trouble understanding the different login paths on the CLI.
The default login is performed through an OAuth flow with the option
to fallback to a username and PAT login using the `docker login -u
<username>` option.

This patch improves the text around `docker login`, indicating:
1. The username is shown when already authenticated
2. When not authenticated, the OAuth login flow explains the fallback
clearly to the user and indicates a PAT can be used instead of a
password.
3. The password prompt now explicitly states that it accepts a PAT.

Signed-off-by: Alano Terblanche <[email protected]>
@Benehiko Benehiko requested review from thaJeztah and a team as code owners January 28, 2025 15:14
@Benehiko Benehiko requested a review from vvoland January 28, 2025 15:33
@Benehiko
Copy link
Member Author

@vvoland please take another look, added some additional changes and regenerated the documents

@@ -178,7 +178,7 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
}
}()

argPassword, err = PromptForInput(ctx, cli.In(), cli.Out(), "Password: ")
argPassword, err = PromptForInput(ctx, cli.In(), cli.Out(), "Password/PAT: ")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PAT feels a bit awkward as a prompt. @thaJeztah @laurazard any opinions on this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm a bit unsure. I think it's nice to be explicit (we could even say secret!) but I think in general, password is what's expected by users, and other CLIs that also accept other types of secrets usually default to password.

Comment on lines 56 to 57
flags.StringVarP(&opts.password, "password", "p", "", "Password/PAT")
flags.BoolVar(&opts.passwordStdin, "password-stdin", false, "Take the password/PAT from stdin")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about expanding the acronym in the description?

Suggested change
flags.StringVarP(&opts.password, "password", "p", "", "Password/PAT")
flags.BoolVar(&opts.passwordStdin, "password-stdin", false, "Take the password/PAT from stdin")
flags.StringVarP(&opts.password, "password", "p", "", "Password or Personal Access Token (PAT)")
flags.BoolVar(&opts.passwordStdin, "password-stdin", false, "Take the password/PAT from stdin")

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can expand it

@Benehiko Benehiko self-assigned this Jan 29, 2025
@@ -178,7 +178,7 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
}
}()

argPassword, err = PromptForInput(ctx, cli.In(), cli.Out(), "Password: ")
argPassword, err = PromptForInput(ctx, cli.In(), cli.Out(), "Password/PAT: ")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm a bit unsure. I think it's nice to be explicit (we could even say secret!) but I think in general, password is what's expected by users, and other CLIs that also accept other types of secrets usually default to password.

_, _ = fmt.Fprintf(dockerCli.Out(), " [Username: %s]", authConfig.Username)
}

_, _ = fmt.Fprintf(dockerCli.Out(), "\nTo login with a different account, run 'docker logout' followed by 'docker login'\n\n")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clearer for sure! I wish we could improve this eventually. Maybe in the future we can do something like prompt the user, if TTY – something like Found credentials for index.docker.io. Reuse credentials (Y/n)?

WDYT @thaJeztah @vvoland ?

@@ -93,7 +93,8 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
}

_, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB-BASED LOGIN"))
_, _ = fmt.Fprintln(w, "To sign in with credentials on the command line, use 'docker login -u <username>'")
_, _ = fmt.Fprintln(w, "> To sign in with username and PAT credentials on the command line, use 'docker login -u <username>'")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...username and PAT credentials sounds weird (weirder than it already does).

Either keep it as is, which isn't great but works for password/PAT/whatever, or we should reword this.

@@ -93,7 +93,8 @@ func (m *OAuthManager) LoginDevice(ctx context.Context, w io.Writer) (*types.Aut
}

_, _ = fmt.Fprintln(w, aec.Bold.Apply("\nUSING WEB-BASED LOGIN"))
_, _ = fmt.Fprintln(w, "To sign in with credentials on the command line, use 'docker login -u <username>'")
_, _ = fmt.Fprintln(w, "> To sign in with username and PAT credentials on the command line, use 'docker login -u <username>'")
_, _ = fmt.Fprintln(w, "> When prompted to enter a password, enter the PAT retrieved from: "+aec.Underline.Apply("https://app.docker.com/settings"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??? This feels like the CLI going around the CLIs back and telling users to do something else 😅

Users can use PATs, but telling users explicitly to use PATs from the Web login prompt feels weird when they can also use passwords. And it turns an already long prompt that most users don't read all the way through even longer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thoughts @dvdksn ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, making this prompt even longer will have the opposite effect I think. The longer it is, the less likely a user is to read it at all. That's why we were trying to keep it as terse as possible in the first iteration.

Copy link
Contributor

@dvdksn dvdksn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Organizational Access Tokens (OAT)?

I think in general I would prefer if we used terminology like "Credential login" vs "Device login", where credential login encompasses username+pw/pat/oat. I don't like the idea of listing all the possible options in the CLI.

Signed-off-by: Alano Terblanche <[email protected]>
@@ -178,7 +179,15 @@ func PromptUserForCredentials(ctx context.Context, cli Cli, argUser, argPassword
}
}()

argPassword, err = PromptForInput(ctx, cli.In(), cli.Out(), "Password: ")
var credentialPrompt strings.Builder
credentialPrompt.WriteString(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could reuse the Info -> printing from image push, it also handles the non-tty vs tty output:

func printNote(dockerCli command.Cli, format string, args ...any) {
if dockerCli.Err().IsTerminal() {
format = strings.ReplaceAll(format, "--platform", aec.Bold.Apply("--platform"))
}
header := " Info -> "
padding := len(header)
if dockerCli.Err().IsTerminal() {
padding = len("i Info > ")
header = aec.Bold.Apply(aec.LightCyanB.Apply(aec.BlackF.Apply("i")) + " " + aec.LightCyanF.Apply("Info → "))
}
_, _ = fmt.Fprint(dockerCli.Err(), header)
s := fmt.Sprintf(format, args...)
for idx, line := range strings.Split(s, "\n") {
if idx > 0 {
_, _ = fmt.Fprint(dockerCli.Err(), strings.Repeat(" ", padding))
}
_, _ = fmt.Fprintln(dockerCli.Err(), aec.Italic.Apply(line))
}
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants