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