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:
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.
implemented by allowing people to provide their own http client go-openapi/runtime#21
@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?
@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)
Most helpful comment
@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 aRuntimeusing https://godoc.org/github.com/go-openapi/runtime/client#NewWithClient.(mostly writing this as a note to people Googling for how to solve this)