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

add oauth2 support in the client #185

Closed
casualjim opened this issue Dec 29, 2015 · 3 comments
Closed

add oauth2 support in the client #185

casualjim opened this issue Dec 29, 2015 · 3 comments

Comments

@casualjim
Copy link
Member

Fully support the auth schemes by swagger in the client generation.

OAuth2 authentication for clients in golang is most probably only applicable to these grant types:

  • resource owner password
  • client credentials for an application using its own API
  • refresh token flow

So the client should know how to get to an access token for those grant types, and the client needs to get a config option for the default grant type.

In addition to those forms of token exchanges the client also needs to support the bearer token scheme.

2FA is out of scope for the moment.

@casualjim
Copy link
Member Author

implemented by allowing people to provide their own http client go-openapi/runtime#21

@ewilde
Copy link

ewilde commented Oct 15, 2017

@casualjim I'm not that familiar with golang, so I struggled to see how to add the the bearer token for use with client credentials grant.

I got it working by exporting the runtime.do function i.e. Do and then creating a custom Runtime and setting runtime.Do to my implementation below:

func NewAuthenticatedClient(config *client.TransportConfig) *AuthenticatedClient {
	a := &AuthenticatedClientCheckRedirect{}
	h := &http.Client{
		Transport: http.DefaultTransport,
		CheckRedirect: a.CheckRedirect,
	}

	rt := rc.NewWithClient(config.Host, config.BasePath, config.Schemes, h)
	authClient := &AuthenticatedClient{
		ApiClients: client.New(rt, strfmt.Default),
		HttpClient: h,
		Config: config,
	}

	rt.Consumers["application/vnd.api+json;charset=UTF-8"] = runtime.JSONConsumer()
	rt.Consumers["application/vnd.api+json"] = runtime.JSONConsumer()
	rt.Do = authClient.Do

	return authClient
}

func (r *AuthenticatedClient) Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
	if client == nil {
		client = r.HttpClient
	}

	if len(r.AccessToken) > 0 {
		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", r.AccessToken))
	}

	resp, err := client.Do(req.WithContext(ctx))
	// If we got an error, and the context has been canceled,
	// the context's error is probably more useful.
	if err != nil {
		select {
		case <-ctx.Done():
			err = ctx.Err()
		default:
		}
	}
	return resp, err
}

func (r *AuthenticatedClient) Login(clientId string, clientSecret string) error {

	mpbody := bytes.NewBuffer(nil)
	writer := multipart.NewWriter(mpbody)
	_ = writer.WriteField("grant_type", "client_credentials")
	writer.Close()
	req, _ := http.NewRequest("POST", "/oauth2/token", mpbody)
	req.URL.Host = r.Config.Host
	req.URL.Path = path.Join(r.Config.BasePath, req.URL.Path)
	req.URL.Scheme = r.Config.Schemes[0]

	req.Header.Set("Content-Type", writer.FormDataContentType())
	encoded := base64.StdEncoding.EncodeToString([]byte(clientId + ":" + clientSecret))
	req.Header.Set("Authorization", "Basic "+encoded)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err.Error())
	}

	loginResponse, err := getLoginResponse([]byte(body))

	if err != nil {
		return err
	}

	r.AccessToken = loginResponse.AccessToken
	return nil
}

That fact that I had to make the do method public makes me think there is probably a better way to do this?

@robinwassen
Copy link

@ewilde - I think the thought is that you can use any http.Client, therefore you can create an oauth2 client using https://godoc.org/golang.org/x/oauth2#NewClient and create a Runtime using https://godoc.org/github.com/go-openapi/runtime/client#NewWithClient.

(mostly writing this as a note to people Googling for how to solve this)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants