1// Package oauth is a library for Go client applications that need to perform OAuth authorization 2// against a server, typically GitHub.com. 3package oauth 4 5import ( 6 "errors" 7 "fmt" 8 "io" 9 "net/http" 10 "net/url" 11 12 "github.com/cli/oauth/api" 13 "github.com/cli/oauth/device" 14) 15 16type httpClient interface { 17 PostForm(string, url.Values) (*http.Response, error) 18} 19 20// Host defines the endpoints used to authorize against an OAuth server. 21type Host struct { 22 DeviceCodeURL string 23 AuthorizeURL string 24 TokenURL string 25} 26 27// GitHubHost constructs a Host from the given URL to a GitHub instance. 28func GitHubHost(hostURL string) *Host { 29 u, _ := url.Parse(hostURL) 30 31 return &Host{ 32 DeviceCodeURL: fmt.Sprintf("%s://%s/login/device/code", u.Scheme, u.Host), 33 AuthorizeURL: fmt.Sprintf("%s://%s/login/oauth/authorize", u.Scheme, u.Host), 34 TokenURL: fmt.Sprintf("%s://%s/login/oauth/access_token", u.Scheme, u.Host), 35 } 36} 37 38// Flow facilitates a single OAuth authorization flow. 39type Flow struct { 40 // The hostname to authorize the app with. 41 // 42 // Deprecated: Use Host instead. 43 Hostname string 44 // Host configuration to authorize the app with. 45 Host *Host 46 // OAuth scopes to request from the user. 47 Scopes []string 48 // OAuth application ID. 49 ClientID string 50 // OAuth application secret. Only applicable in web application flow. 51 ClientSecret string 52 // The localhost URI for web application flow callback, e.g. "http://127.0.0.1/callback". 53 CallbackURI string 54 55 // Display a one-time code to the user. Receives the code and the browser URL as arguments. Defaults to printing the 56 // code to the user on Stdout with instructions to copy the code and to press Enter to continue in their browser. 57 DisplayCode func(string, string) error 58 // Open a web browser at a URL. Defaults to opening the default system browser. 59 BrowseURL func(string) error 60 // Render an HTML page to the user upon completion of web application flow. The default is to 61 // render a simple message that informs the user they can close the browser tab and return to the app. 62 WriteSuccessHTML func(io.Writer) 63 64 // The HTTP client to use for API POST requests. Defaults to http.DefaultClient. 65 HTTPClient httpClient 66 // The stream to listen to keyboard input on. Defaults to os.Stdin. 67 Stdin io.Reader 68 // The stream to print UI messages to. Defaults to os.Stdout. 69 Stdout io.Writer 70} 71 72// DetectFlow tries to perform Device flow first and falls back to Web application flow. 73func (oa *Flow) DetectFlow() (*api.AccessToken, error) { 74 accessToken, err := oa.DeviceFlow() 75 if errors.Is(err, device.ErrUnsupported) { 76 return oa.WebAppFlow() 77 } 78 return accessToken, err 79} 80