Skip to content

Allow making raw HTTP POST requests to the authz server #463

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
30 changes: 18 additions & 12 deletions internal/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func cloneURLValues(v url.Values) url.Values {
return v2
}

func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) {
func PostRawRequest(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*http.Response, error) {
needsAuthStyleProbe := authStyle == 0
if needsAuthStyleProbe {
if style, ok := lookupAuthStyle(tokenURL); ok {
Expand All @@ -199,8 +199,11 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
if err != nil {
return nil, err
}
token, err := doTokenRoundTrip(ctx, req)
if err != nil && needsAuthStyleProbe {
resp, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
if err != nil {
return nil, err // transport errors are not related to auth style
}
if resp.StatusCode >= 400 && resp.StatusCode <= 499 && needsAuthStyleProbe {
// If we get an error, assume the server wants the
// clientID & clientSecret in a different form.
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
Expand All @@ -215,24 +218,27 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
// So just try both ways.
authStyle = AuthStyleInParams // the second way we'll try
req, _ = newTokenRequest(tokenURL, clientID, clientSecret, v, authStyle)
token, err = doTokenRoundTrip(ctx, req)
resp, err = ctxhttp.Do(ctx, ContextClient(ctx), req)
}
if needsAuthStyleProbe && err == nil {
if needsAuthStyleProbe && err == nil && (resp.StatusCode < 400 || resp.StatusCode > 499) {
setAuthStyle(tokenURL, authStyle)
}
// Don't overwrite `RefreshToken` with an empty value
// if this was a token refreshing request.
return resp, err
}

func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle) (*Token, error) {
resp, err := PostRawRequest(ctx, clientID, clientSecret, tokenURL, v, authStyle)
if err != nil {
return nil, err
}
token, err := parseTokenResponse(resp)
if token != nil && token.RefreshToken == "" {
token.RefreshToken = v.Get("refresh_token")
}
return token, err
}

func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
r, err := ctxhttp.Do(ctx, ContextClient(ctx), req)
if err != nil {
return nil, err
}
func parseTokenResponse(r *http.Response) (*Token, error) {
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
r.Body.Close()
if err != nil {
Expand Down
12 changes: 12 additions & 0 deletions oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOpti
return retrieveToken(ctx, c, v)
}

// PostRawRequest makes a raw HTTP POST request to the given endpoint, which is assumed to be an endpoint of the
// authorization server.
//
// This can be used to invoke endpoints which are non-standard, or not otherwise supported by this library (e.g., token
// revocation), ensuring the use of a consistent logic for, e.g., automatically inferring authentication styles.
//
// Note that a non-2xx response is passed through as-is, without setting an error value. Nothing is ever read from the
// response body.
func (c *Config) PostRawRequest(ctx context.Context, endpoint string, v url.Values) (*http.Response, error) {
return internal.PostRawRequest(ctx, c.ClientID, c.ClientSecret, endpoint, v, internal.AuthStyle(c.Endpoint.AuthStyle))
}

// Client returns an HTTP client using the provided token.
// The token will auto-refresh as necessary. The underlying
// HTTP transport will be obtained using the provided context.
Expand Down