github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/pkg/cmd/auth/refresh/refresh.go (about) 1 package refresh 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/AlecAivazis/survey/v2" 8 "github.com/MakeNowJust/heredoc" 9 "github.com/cli/cli/internal/authflow" 10 "github.com/cli/cli/internal/config" 11 "github.com/cli/cli/pkg/cmd/auth/shared" 12 "github.com/cli/cli/pkg/cmdutil" 13 "github.com/cli/cli/pkg/iostreams" 14 "github.com/cli/cli/pkg/prompt" 15 "github.com/spf13/cobra" 16 ) 17 18 type RefreshOptions struct { 19 IO *iostreams.IOStreams 20 Config func() (config.Config, error) 21 22 MainExecutable string 23 24 Hostname string 25 Scopes []string 26 AuthFlow func(config.Config, *iostreams.IOStreams, string, []string) error 27 28 Interactive bool 29 } 30 31 func NewCmdRefresh(f *cmdutil.Factory, runF func(*RefreshOptions) error) *cobra.Command { 32 opts := &RefreshOptions{ 33 IO: f.IOStreams, 34 Config: f.Config, 35 AuthFlow: func(cfg config.Config, io *iostreams.IOStreams, hostname string, scopes []string) error { 36 _, err := authflow.AuthFlowWithConfig(cfg, io, hostname, "", scopes) 37 return err 38 }, 39 MainExecutable: f.Executable, 40 } 41 42 cmd := &cobra.Command{ 43 Use: "refresh", 44 Args: cobra.ExactArgs(0), 45 Short: "Refresh stored authentication credentials", 46 Long: heredoc.Doc(`Expand or fix the permission scopes for stored credentials 47 48 The --scopes flag accepts a comma separated list of scopes you want your gh credentials to have. If 49 absent, this command ensures that gh has access to a minimum set of scopes. 50 `), 51 Example: heredoc.Doc(` 52 $ gh auth refresh --scopes write:org,read:public_key 53 # => open a browser to add write:org and read:public_key scopes for use with gh api 54 55 $ gh auth refresh 56 # => open a browser to ensure your authentication credentials have the correct minimum scopes 57 `), 58 RunE: func(cmd *cobra.Command, args []string) error { 59 opts.Interactive = opts.IO.CanPrompt() 60 61 if !opts.Interactive && opts.Hostname == "" { 62 return &cmdutil.FlagError{Err: errors.New("--hostname required when not running interactively")} 63 } 64 65 if runF != nil { 66 return runF(opts) 67 } 68 return refreshRun(opts) 69 }, 70 } 71 72 cmd.Flags().StringVarP(&opts.Hostname, "hostname", "h", "", "The GitHub host to use for authentication") 73 cmd.Flags().StringSliceVarP(&opts.Scopes, "scopes", "s", nil, "Additional authentication scopes for gh to have") 74 75 return cmd 76 } 77 78 func refreshRun(opts *RefreshOptions) error { 79 cfg, err := opts.Config() 80 if err != nil { 81 return err 82 } 83 84 candidates, err := cfg.Hosts() 85 if err != nil { 86 return err 87 } 88 if len(candidates) == 0 { 89 return fmt.Errorf("not logged in to any hosts. Use 'gh auth login' to authenticate with a host") 90 } 91 92 hostname := opts.Hostname 93 if hostname == "" { 94 if len(candidates) == 1 { 95 hostname = candidates[0] 96 } else { 97 err := prompt.SurveyAskOne(&survey.Select{ 98 Message: "What account do you want to refresh auth for?", 99 Options: candidates, 100 }, &hostname) 101 102 if err != nil { 103 return fmt.Errorf("could not prompt: %w", err) 104 } 105 } 106 } else { 107 var found bool 108 for _, c := range candidates { 109 if c == hostname { 110 found = true 111 break 112 } 113 } 114 115 if !found { 116 return fmt.Errorf("not logged in to %s. use 'gh auth login' to authenticate with this host", hostname) 117 } 118 } 119 120 if err := cfg.CheckWriteable(hostname, "oauth_token"); err != nil { 121 var roErr *config.ReadOnlyEnvError 122 if errors.As(err, &roErr) { 123 fmt.Fprintf(opts.IO.ErrOut, "The value of the %s environment variable is being used for authentication.\n", roErr.Variable) 124 fmt.Fprint(opts.IO.ErrOut, "To refresh credentials stored in GitHub CLI, first clear the value from the environment.\n") 125 return cmdutil.SilentError 126 } 127 return err 128 } 129 130 var additionalScopes []string 131 132 credentialFlow := &shared.GitCredentialFlow{} 133 gitProtocol, _ := cfg.Get(hostname, "git_protocol") 134 if opts.Interactive && gitProtocol == "https" { 135 if err := credentialFlow.Prompt(hostname); err != nil { 136 return err 137 } 138 additionalScopes = append(additionalScopes, credentialFlow.Scopes()...) 139 } 140 141 if err := opts.AuthFlow(cfg, opts.IO, hostname, append(opts.Scopes, additionalScopes...)); err != nil { 142 return err 143 } 144 145 if credentialFlow.ShouldSetup() { 146 username, _ := cfg.Get(hostname, "user") 147 password, _ := cfg.Get(hostname, "oauth_token") 148 if err := credentialFlow.Setup(hostname, username, password); err != nil { 149 return err 150 } 151 } 152 153 return nil 154 }