diff --git a/google/google.go b/google/google.go index 03113bb..726650c 100644 --- a/google/google.go +++ b/google/google.go @@ -81,13 +81,13 @@ type ComputeEngineConfig struct{} // NewConfig creates a new OAuth2 config that uses Google // endpoints. -func NewConfig(opts *oauth2.Options) (oauth2.Config, error) { +func NewConfig(opts *oauth2.Options) (*oauth2.Config, error) { return oauth2.NewConfig(opts, uriGoogleAuth, uriGoogleToken) } // NewServiceAccountConfig creates a new JWT config that can // fetch Bearer JWT tokens from Google endpoints. -func NewServiceAccountConfig(opts *oauth2.JWTOptions) (oauth2.JWTConfig, error) { +func NewServiceAccountConfig(opts *oauth2.JWTOptions) (*oauth2.JWTConfig, error) { return oauth2.NewJWTConfig(opts, uriGoogleToken) } diff --git a/jwt.go b/jwt.go index ec3c01d..de78d1e 100644 --- a/jwt.go +++ b/jwt.go @@ -38,36 +38,42 @@ type JWTOptions struct { // NewJWTConfig creates a new configuration with the specified options // and OAuth2 provider endpoint. -func NewJWTConfig(opts *JWTOptions, aud string) (conf JWTConfig, err error) { +func NewJWTConfig(opts *JWTOptions, aud string) (*JWTConfig, error) { contents, err := ioutil.ReadFile(opts.PemFilename) if err != nil { - return + return nil, err } - conf = &jwtConfig{opts: opts, aud: aud, signature: contents} - return + return &JWTConfig{opts: opts, aud: aud, signature: contents}, nil } -type jwtConfig struct { +// JWTConfig represents an OAuth 2.0 provider and client options to +// provide authorized transports with a Bearer JWT token. +type JWTConfig struct { opts *JWTOptions aud string signature []byte } +// Options returns JWT options. +func (c *JWTConfig) Options() *JWTOptions { + return c.opts +} + // NewTransport creates a transport that is authorize with the // parent JWT configuration. -func (c *jwtConfig) NewTransport() (Transport, error) { +func (c *JWTConfig) NewTransport() (Transport, error) { return NewAuthorizedTransport(c, &Token{}), nil } // NewTransportWithUser creates a transport that is authorized by // the client and impersonates the specified user. -func (c *jwtConfig) NewTransportWithUser(user string) (Transport, error) { +func (c *JWTConfig) NewTransportWithUser(user string) (Transport, error) { return NewAuthorizedTransport(c, &Token{Subject: user}), nil } // fetchToken retrieves a new access token and updates the existing token // with the newly fetched credentials. -func (c *jwtConfig) FetchToken(existing *Token) (token *Token, err error) { +func (c *JWTConfig) FetchToken(existing *Token) (token *Token, err error) { if existing == nil { existing = &Token{} diff --git a/oauth2.go b/oauth2.go index b492ff6..a99a681 100644 --- a/oauth2.go +++ b/oauth2.go @@ -5,7 +5,7 @@ // Example usage: // // // Specify your configuration. (typically as a global variable) -// var config = oauth2.NewConfig(&oauth2.Options{ +// config := oauth2.NewConfig(&oauth2.Options{ // ClientID: YOUR_CLIENT_ID, // ClientSecret: YOUR_CLIENT_SECRET, // RedirectURL: "http://you.example.org/handler", @@ -102,43 +102,10 @@ type Options struct { ApprovalPrompt string `json:"omit"` } -// Config represents an OAuth 2.0 provider and client options to -// provide authorized transports. -type Config interface { - // NewTransport creates a transport which is configured to be - // authorized with the config provided. - NewTransport() (Transport, error) - - // NewTransportWithCode creates a transport after going through - // the OAuth 2.0 exchange flow to retrieve a valid token from - // the exchange server. - NewTransportWithCode(exchangeCode string) (Transport, error) - - // AuthCodeURL generates a URL to the consent page. - AuthCodeURL(state string) (string, error) - - // Exchange ecxhanges the code with the provider to retrieve - // a new access token. - Exchange(exchangeCode string) (*Token, error) -} - -// Config represents an OAuth 2.0 provider and client options to -// provide authorized transports with a Bearer JWT token. -type JWTConfig interface { - // NewTransport creates a transport which is configured to - // be authorized with OAuth 2.0 JWT Bearer flow. - NewTransport() (Transport, error) - - // NewTransportWithUser creates a transport which is configured - // to be authorized with OAuth 2.0 JWT Bearer flow and - // impersonates the provided user. - NewTransportWithUser(user string) (Transport, error) -} - // NewConfig creates a generic OAuth 2.0 configuration that talks // to an OAuth 2.0 provider specified with authURL and tokenURL. -func NewConfig(opts *Options, authURL, tokenURL string) (Config, error) { - conf := &config{ +func NewConfig(opts *Options, authURL, tokenURL string) (*Config, error) { + conf := &Config{ opts: opts, authURL: authURL, tokenURL: tokenURL, @@ -149,8 +116,8 @@ func NewConfig(opts *Options, authURL, tokenURL string) (Config, error) { return conf, nil } -// config represents the configuration of an OAuth 2.0 consumer client. -type config struct { +// Config represents the configuration of an OAuth 2.0 consumer client. +type Config struct { opts *Options // AuthURL is the URL the user will be directed to // in order to grant access. @@ -159,9 +126,14 @@ type config struct { tokenURL string } +// Options returns options. +func (c *Config) Options() *Options { + return c.opts +} + // AuthCodeURL returns a URL to OAuth 2.0 provider's consent page // that asks for permissions for the required scopes explicitly. -func (c *config) AuthCodeURL(state string) (authURL string, err error) { +func (c *Config) AuthCodeURL(state string) (authURL string, err error) { u, err := url.Parse(c.authURL) if err != nil { return @@ -192,7 +164,7 @@ func (c *config) AuthCodeURL(state string) (authURL string, err error) { // t, _ := c.NewTransport() // t.SetToken(validToken) // -func (c *config) NewTransport() (Transport, error) { +func (c *Config) NewTransport() (Transport, error) { return NewAuthorizedTransport(c, nil), nil } @@ -200,7 +172,7 @@ func (c *config) NewTransport() (Transport, error) { // the provider to fetch a new access token (and refresh token). Once // it succesffully retrieves a new token, creates a new transport // authorized with it. -func (c *config) NewTransportWithCode(exchangeCode string) (Transport, error) { +func (c *Config) NewTransportWithCode(exchangeCode string) (Transport, error) { token, err := c.Exchange(exchangeCode) if err != nil { return nil, err @@ -210,7 +182,7 @@ func (c *config) NewTransportWithCode(exchangeCode string) (Transport, error) { // Exchange exchanges the exchange code with the OAuth 2.0 provider // to retrieve a new access token. -func (c *config) Exchange(exchangeCode string) (*Token, error) { +func (c *Config) Exchange(exchangeCode string) (*Token, error) { token := &Token{} err := c.updateToken(token, url.Values{ "grant_type": {"authorization_code"}, @@ -227,7 +199,7 @@ func (c *config) Exchange(exchangeCode string) (*Token, error) { // FetchToken retrieves a new access token and updates the existing token // with the newly fetched credentials. If existing token doesn't // contain a refresh token, it returns an error. -func (c *config) FetchToken(existing *Token) (*Token, error) { +func (c *Config) FetchToken(existing *Token) (*Token, error) { if existing == nil || existing.RefreshToken == "" { return nil, errors.New("cannot fetch access token without refresh token.") } @@ -239,7 +211,7 @@ func (c *config) FetchToken(existing *Token) (*Token, error) { } // Checks if all required configuration fields have non-zero values. -func (c *config) validate() error { +func (c *Config) validate() error { if c.opts.ClientID == "" { return errors.New("A client ID should be provided.") } @@ -262,7 +234,7 @@ func (c *config) validate() error { return nil } -func (c *config) updateToken(tok *Token, v url.Values) error { +func (c *Config) updateToken(tok *Token, v url.Values) error { v.Set("client_id", c.opts.ClientID) v.Set("client_secret", c.opts.ClientSecret) r, err := (&http.Client{Transport: DefaultTransport}).PostForm(c.tokenURL, v) diff --git a/oauth2_test.go b/oauth2_test.go index 9138f62..e8b8715 100644 --- a/oauth2_test.go +++ b/oauth2_test.go @@ -15,7 +15,7 @@ func (t *mockTransport) RoundTrip(req *http.Request) (resp *http.Response, err e return t.rt(req) } -func newTestConf() Config { +func newTestConf() *Config { conf, _ := NewConfig(&Options{ ClientID: "CLIENT_ID", ClientSecret: "CLIENT_SECRET", @@ -77,7 +77,7 @@ func TestExchangingTransport(t *testing.T) { func TestFetchWithNoRedirect(t *testing.T) { DefaultTransport = http.DefaultTransport - fetcher := newTestConf().(TokenFetcher) + fetcher := newTestConf() _, err := fetcher.FetchToken(&Token{}) if err == nil { t.Fatalf("Fetch should return an error if no refresh token is set")