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

feat: Add support for audience in authorization request #68

Merged
merged 3 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions device/device_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,31 @@ type CodeResponse struct {
Interval int
}

// AuthRequestEditorFn defines the function signature for setting additional form values.
type AuthRequestEditorFn func(*url.Values)

// WithAudience sets the audience parameter in the request.
func WithAudience(audience string) AuthRequestEditorFn {
return func(values *url.Values) {
if audience != "" {
values.Add("audience", audience)
}
}
}

// RequestCode initiates the authorization flow by requesting a code from uri.
func RequestCode(c httpClient, uri string, clientID string, scopes []string) (*CodeResponse, error) {
resp, err := api.PostForm(c, uri, url.Values{
func RequestCode(c httpClient, uri string, clientID string, scopes []string,
optionalRequestParams ...AuthRequestEditorFn) (*CodeResponse, error) {
values := url.Values{
"client_id": {clientID},
"scope": {strings.Join(scopes, " ")},
})
}

for _, fn := range optionalRequestParams {
fn(&values)
}

resp, err := api.PostForm(c, uri, values)
if err != nil {
return nil, err
}
Expand Down
40 changes: 39 additions & 1 deletion device/device_flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func TestRequestCode(t *testing.T) {
url string
clientID string
scopes []string
audience string
}
tests := []struct {
name string
Expand Down Expand Up @@ -126,6 +127,42 @@ func TestRequestCode(t *testing.T) {
},
},
},
{
name: "with audience",
args: args{
http: apiClient{
stubs: []apiStub{
{
body: "verification_uri=http://verify.me&interval=5&expires_in=99&device_code=DEVIC&user_code=123-abc&verification_uri_complete=http://verify.me/?code=123-abc",
status: 200,
contentType: "application/x-www-form-urlencoded; charset=utf-8",
},
},
},
url: "https://github.com/oauth",
clientID: "CLIENT-ID",
scopes: []string{"repo", "gist"},
audience: "https://api.github.com",
},
want: &CodeResponse{
DeviceCode: "DEVIC",
UserCode: "123-abc",
VerificationURI: "http://verify.me",
VerificationURIComplete: "http://verify.me/?code=123-abc",
ExpiresIn: 99,
Interval: 5,
},
posts: []postArgs{
{
url: "https://github.com/oauth",
params: url.Values{
"client_id": {"CLIENT-ID"},
"scope": {"repo gist"},
"audience": {"https://api.github.com"},
},
},
},
},
{
name: "unsupported",
args: args{
Expand Down Expand Up @@ -237,7 +274,8 @@ func TestRequestCode(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := RequestCode(&tt.args.http, tt.args.url, tt.args.clientID, tt.args.scopes)
got, err := RequestCode(&tt.args.http, tt.args.url,
tt.args.clientID, tt.args.scopes, WithAudience(tt.args.audience))
if (err != nil) != (tt.wantErr != "") {
t.Errorf("RequestCode() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
2 changes: 2 additions & 0 deletions oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type Flow struct {
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.
Expand Down
3 changes: 2 additions & 1 deletion oauth_device.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ func (oa *Flow) DeviceFlow() (*api.AccessToken, error) {
host = GitHubHost("https://" + oa.Hostname)
}

code, err := device.RequestCode(httpClient, host.DeviceCodeURL, oa.ClientID, oa.Scopes)
code, err := device.RequestCode(httpClient, host.DeviceCodeURL,
oa.ClientID, oa.Scopes, device.WithAudience(oa.Audience))
if err != nil {
return nil, err
}
Expand Down
1 change: 1 addition & 0 deletions oauth_webapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (oa *Flow) WebAppFlow() (*api.AccessToken, error) {
ClientID: oa.ClientID,
RedirectURI: oa.CallbackURI,
Scopes: oa.Scopes,
Audience: oa.Audience,
AllowSignup: true,
}
browserURL, err := flow.BrowserURL(host.AuthorizeURL, params)
Expand Down
5 changes: 5 additions & 0 deletions webapp/webapp_flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type BrowserParams struct {
ClientID string
RedirectURI string
Scopes []string
Audience string
LoginHandle string
AllowSignup bool
}
Expand All @@ -68,6 +69,10 @@ func (flow *Flow) BrowserURL(baseURL string, params BrowserParams) (string, erro
q.Set("redirect_uri", ru.String())
q.Set("scope", strings.Join(params.Scopes, " "))
q.Set("state", flow.state)

if params.Audience != "" {
q.Set("audience", params.Audience)
}
if params.LoginHandle != "" {
q.Set("login", params.LoginHandle)
}
Expand Down
18 changes: 18 additions & 0 deletions webapp/webapp_flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,24 @@ func TestFlow_BrowserURL(t *testing.T) {
want: "https://github.com/authorize?client_id=CLIENT-ID&redirect_uri=http%3A%2F%2F127.0.0.1%3A12345%2Fhello&scope=repo+read%3Aorg&state=xy%2Fz",
wantErr: false,
},
{
name: "happy path with audience",
fields: fields{
server: server,
state: "xy/z",
},
args: args{
baseURL: "https://github.com/authorize",
params: BrowserParams{
ClientID: "CLIENT-ID",
RedirectURI: "http://127.0.0.1/hello",
Scopes: []string{"repo", "read:org"},
AllowSignup: true,
Audience: "https://api.github.com",
},
},
want: "https://github.com/authorize?audience=https%3A%2F%2Fapi.github.com&client_id=CLIENT-ID&redirect_uri=http%3A%2F%2F127.0.0.1%3A12345%2Fhello&scope=repo+read%3Aorg&state=xy%2Fz",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
Loading