@@ -32,6 +32,8 @@ import (
3232
3333 "github.com/mwitkow/go-conntrack"
3434 "golang.org/x/net/http2"
35+ "golang.org/x/oauth2"
36+ "golang.org/x/oauth2/clientcredentials"
3537 "gopkg.in/yaml.v2"
3638)
3739
@@ -108,12 +110,23 @@ func (u URL) MarshalYAML() (interface{}, error) {
108110 return nil , nil
109111}
110112
113+ // OAuth2 is the oauth2 client configuration.
114+ type OAuth2 struct {
115+ ClientID string `yaml:"client_id"`
116+ ClientSecret Secret `yaml:"client_secret"`
117+ Scopes []string `yaml:"scopes,omitempty"`
118+ TokenURL string `yaml:"token_url"`
119+ EndpointParams map [string ]string `yaml:"endpoint_params,omitempty"`
120+ }
121+
111122// HTTPClientConfig configures an HTTP client.
112123type HTTPClientConfig struct {
113124 // The HTTP basic authentication credentials for the targets.
114125 BasicAuth * BasicAuth `yaml:"basic_auth,omitempty"`
115126 // The HTTP authorization credentials for the targets.
116127 Authorization * Authorization `yaml:"authorization,omitempty"`
128+ // The OAuth2 client credentials used to fetch a token for the targets.
129+ OAuth2 * OAuth2 `yaml:"oauth2,omitempty"`
117130 // The bearer token for the targets. Deprecated in favour of
118131 // Authorization.Credentials.
119132 BearerToken Secret `yaml:"bearer_token,omitempty"`
@@ -148,8 +161,8 @@ func (c *HTTPClientConfig) Validate() error {
148161 if len (c .BearerToken ) > 0 && len (c .BearerTokenFile ) > 0 {
149162 return fmt .Errorf ("at most one of bearer_token & bearer_token_file must be configured" )
150163 }
151- if c .BasicAuth != nil && (len (c .BearerToken ) > 0 || len (c .BearerTokenFile ) > 0 ) {
152- return fmt .Errorf ("at most one of basic_auth, bearer_token & bearer_token_file must be configured" )
164+ if ( c .BasicAuth != nil || c . OAuth2 != nil ) && (len (c .BearerToken ) > 0 || len (c .BearerTokenFile ) > 0 ) {
165+ return fmt .Errorf ("at most one of basic_auth, oauth2, bearer_token & bearer_token_file must be configured" )
153166 }
154167 if c .BasicAuth != nil && (string (c .BasicAuth .Password ) != "" && c .BasicAuth .PasswordFile != "" ) {
155168 return fmt .Errorf ("at most one of basic_auth password & password_file must be configured" )
@@ -168,8 +181,8 @@ func (c *HTTPClientConfig) Validate() error {
168181 if strings .ToLower (c .Authorization .Type ) == "basic" {
169182 return fmt .Errorf (`authorization type cannot be set to "basic", use "basic_auth" instead` )
170183 }
171- if c .BasicAuth != nil {
172- return fmt .Errorf ("at most one of basic_auth & authorization must be configured" )
184+ if c .BasicAuth != nil || c . OAuth2 != nil {
185+ return fmt .Errorf ("at most one of basic_auth, oauth2 & authorization must be configured" )
173186 }
174187 } else {
175188 if len (c .BearerToken ) > 0 {
@@ -183,6 +196,9 @@ func (c *HTTPClientConfig) Validate() error {
183196 c .BearerTokenFile = ""
184197 }
185198 }
199+ if c .BasicAuth != nil && c .OAuth2 != nil {
200+ return fmt .Errorf ("at most one of basic_auth, oauth2 & authorization must be configured" )
201+ }
186202 return nil
187203}
188204
@@ -329,6 +345,10 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
329345 if cfg .BasicAuth != nil {
330346 rt = NewBasicAuthRoundTripper (cfg .BasicAuth .Username , cfg .BasicAuth .Password , cfg .BasicAuth .PasswordFile , rt )
331347 }
348+
349+ if cfg .OAuth2 != nil {
350+ rt = cfg .OAuth2 .NewOAuth2RoundTripper (context .Background (), rt )
351+ }
332352 // Return a new configured RoundTripper.
333353 return rt , nil
334354 }
@@ -442,6 +462,32 @@ func (rt *basicAuthRoundTripper) CloseIdleConnections() {
442462 }
443463}
444464
465+ func (c * OAuth2 ) NewOAuth2RoundTripper (ctx context.Context , next http.RoundTripper ) http.RoundTripper {
466+ config := & clientcredentials.Config {
467+ ClientID : c .ClientID ,
468+ ClientSecret : string (c .ClientSecret ),
469+ Scopes : c .Scopes ,
470+ TokenURL : c .TokenURL ,
471+ EndpointParams : mapToValues (c .EndpointParams ),
472+ }
473+
474+ tokenSource := config .TokenSource (ctx )
475+
476+ return & oauth2.Transport {
477+ Base : next ,
478+ Source : tokenSource ,
479+ }
480+ }
481+
482+ func mapToValues (m map [string ]string ) url.Values {
483+ v := url.Values {}
484+ for name , value := range m {
485+ v .Set (name , value )
486+ }
487+
488+ return v
489+ }
490+
445491// cloneRequest returns a clone of the provided *http.Request.
446492// The clone is a shallow copy of the struct and its Header map.
447493func cloneRequest (r * http.Request ) * http.Request {
0 commit comments