goauth

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 18, 2021 License: MIT Imports: 21 Imported by: 2

README

Goauth for Go

Build Status

The goauth package contains a simplified implementation of OAuth 1.0 and OAuth 2.0 spec for the Go programming language.

Installation

go get "github.com/rchargel/goauth"

Import

import "github.com/rchargel/goauth"

Documentation

The package documentation can be found at http://godoc.org/github.com/rchargel/goauth.

Here is the project page and a quick tutorial.

Dependencies

  • golang.org/x/oauth2 - the OAuth 2.0 service provider wraps this API.
  • gopkg.in/yaml.v2 - a YAML file reader.

Implementation Description

Package goauth is a simple to use and implement tool to configure OAuth authentication for your application or service. It relies on some of the OAuth tools already available for Go, but adds in some structure to reduce the complexity of your implementation. The intent is to make authentication easy by reducing the pain points to just a couple of configuration parameters.

This package provides two OAuth implementations, Version 1.0 and Version 2.0. For version 2.0 implementations the sequence of events is fairly straightforward.

Browser                    Server                   Provider
   |                          |                          |
   # GET: /oauth/provider     |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |            Send Redirect #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   # Redirect to provider login                          |
   #==>==>==>==>==>==>==>==>==|==>==>==>==>==>==>==>==>=>#
   |                          |                          # User logs in
   |                          | Redirect to callback URL #
   #<=<==<==<==<==<==<==<==<==|==<==<==<==<==<==<==<==<==#
   # GET: Callback URL        |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |                          # GET: User Info           |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #<=<==<==<==<==<==<==<==<==#
   |                          # Process User             |
   |                          # Create Session           |
   |          Respond To User #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   #                          |                          |

For version 1.0 implementations the sequence of events is slightly more complex, however most of that complexity is hidden from you by the API.

Browser                    Server                    Provider
   |                          |                          |
   # GET: /oauth/provider     |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |                          # Fetch OAuth Token        |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #                          # Auth Request
   |                          #  Return Token and Secret #
   |                          #<=<==<==<==<==<==<==<==<==#
   |            Send Redirect #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   # Redirect to provider login                          |
   #==>==>==>==>==>==>==>==>==|==>==>==>==>==>==>==>==>=>#
   |                          |                          # User logs in
   |                          | Redirect to callback URL #
   #<=<==<==<==<==<==<==<==<==|==<==<==<==<==<==<==<==<==#
   # GET: Callback URL        |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |                          # Fetch Access Token       |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #                          # Auth Request
   |                          #      Return Access Token #
   |                          #<=<==<==<==<==<==<==<==<==#
   |                          # GET: User Info           |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #<=<==<==<==<==<==<==<==<==#
   |                          # Process User             |
   |                          # Create Session           |
   |          Respond To User #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   #                          |                          |

Testing

So far, I have only tested this API with the following OAuth Providers:

  • OAuth 2.0
    • Google
    • Facebook
  • OAuth 1.0
    • Twitter

Contact Me

Contact me with any questions or comments through my website: http://zcarioca.net.

Documentation

Overview

Package goauth is a simple to use and implement tool to configure OAuth authentication for your application or service. It relies on some of the OAuth tools already available for Go, but adds in some structure to reduce the complexity of your implementation. The intent is to make authentication easy by reducing the pain points to just a couple of configuration parameters.

This package provides two OAuth implementations, Version 1.0 and Version 2.0. For version 2.0 implementations the sequence of events is fairly straightforward.

Browser                    Server                   Provider
   |                          |                          |
   # GET: /oauth/provider     |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |            Send Redirect #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   # Redirect to provider login                          |
   #==>==>==>==>==>==>==>==>==|==>==>==>==>==>==>==>==>=>#
   |                          |                          # User logs in
   |                          | Redirect to callback URL #
   #<=<==<==<==<==<==<==<==<==|==<==<==<==<==<==<==<==<==#
   # GET: Callback URL        |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |                          # GET: User Info           |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #<=<==<==<==<==<==<==<==<==#
   |                          # Process User             |
   |                          # Create Session           |
   |          Respond To User #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   #                          |                          |

For version 1.0 implementations the sequence of events is slightly more complex, however most of that complexity is hidden from you by the API.

Browser                    Server                    Provider
   |                          |                          |
   # GET: /oauth/provider     |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |                          # Fetch OAuth Token        |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #                          # Auth Request
   |                          #  Return Token and Secret #
   |                          #<=<==<==<==<==<==<==<==<==#
   |            Send Redirect #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   # Redirect to provider login                          |
   #==>==>==>==>==>==>==>==>==|==>==>==>==>==>==>==>==>=>#
   |                          |                          # User logs in
   |                          | Redirect to callback URL #
   #<=<==<==<==<==<==<==<==<==|==<==<==<==<==<==<==<==<==#
   # GET: Callback URL        |                          |
   #==>==>==>==>==>==>==>==>=>#                          |
   |                          # Fetch Access Token       |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #                          # Auth Request
   |                          #      Return Access Token #
   |                          #<=<==<==<==<==<==<==<==<==#
   |                          # GET: User Info           |
   |                          #==>==>==>==>==>==>==>==>=>#
   |                          #<=<==<==<==<==<==<==<==<==#
   |                          # Process User             |
   |                          # Create Session           |
   |          Respond To User #                          |
   #<=<==<==<==<==<==<==<==<==#                          |
   #                          |                          |

Index

Examples

Constants

View Source
const (
	OAuth1HeaderTransmissionType  = 1 << iota
	OAuth1QueryParamTramssionType = 1 << iota
	OAuth1DefaultTransmissionType = OAuth1HeaderTransmissionType
)

OAuth 1.0 authentication transmission types.

View Source
const (
	OAuthVerbGet     = "GET"
	OAuthVerbPost    = "POST"
	OAuthVerbDefault = OAuthVerbPost
)

OAuth 1.0 Verbs.

View Source
const (
	OAuthVersion1 = "1.0"
	OAuthVersion2 = "2.0"
)

OAuth Versions.

Variables

This section is empty.

Functions

func ConfigureProvidersFromJSON

func ConfigureProvidersFromJSON(fileReader io.Reader, callbackURL string) (map[string]OAuthServiceProvider, error)

ConfigureProvidersFromJSON configures a map of providers using a JSON file.

Example
// in this example I'm hiding the client ID and secret which will be fetched
// from the environment.
os.Setenv("GOOGLE_CLIENT_ID", "abc123")
os.Setenv("GOOGLE_CLIENT_SECRET", "xyz456")
os.Setenv("FACEBOOK_CLIENT_ID", "abc123")
os.Setenv("FACEBOOK_CLIENT_SECRET", "xyz456")
os.Setenv("TWITTER_CLIENT_ID", "abc123")
os.Setenv("TWITTER_CLIENT_SECRET", "xyz456")
jsonString := `{
   "Google":{
      "OAuthVersion":2.0,
      "AuthURL":"https://accounts.google.com/o/oauth2/auth",
      "TokenURL":"https://accounts.google.com/o/oauth2/token",
      "UserInfoURL":"https://www.googleapis.com/oauth2/v2/userinfo",
      "Scopes":[
         "https://www.googleapis.com/auth/userinfo.profile",
         "https://www.googleapis.com/auth/userinfo.email"
      ]
   },
   "Facebook":{
      "OAuthVersion":2.0,
      "AuthURL":"https://www.facebook.com/dialog/oauth",
      "TokenURL":"https://graph.facebook.com/oauth/access_token",
      "UserInfoURL":"https://graph.facebook.com/me?fields=id,first_name,middle_name,last_name,email,picture",
      "Scopes":[
         "email",
         "public_profile"
      ]
   },
   "Twitter":{
      "OAuthVersion":1.0,
      "AuthURL":"https://api.twitter.com/oauth/authorize",
      "TokenURL":"https://api.twitter.com/oauth/access_token",
      "UserInfoURL":"https://api.twitter.com/1.1/account/verify_credentials.json",
      "RequestTokenURL":"https://api.twitter.com/oauth/request_token"
   }
}`

reader := strings.NewReader(jsonString)

providers, err := ConfigureProvidersFromJSON(reader, "http://myhost/oauth/callback/%v")
if err != nil {
	fmt.Println(err.Error())
}

fmt.Printf("Found %d providers.\n", len(providers))
fmt.Printf("The provider for %s is a version %s provider named %s.\n", "google",
	providers["google"].GetOAuthVersion(), providers["google"].GetProviderName())
fmt.Printf("The provider for %s is a version %s provider named %s.\n", "facebook",
	providers["facebook"].GetOAuthVersion(), providers["facebook"].GetProviderName())
fmt.Printf("The provider for %s is a version %s provider named %s.\n", "twitter",
	providers["twitter"].GetOAuthVersion(), providers["twitter"].GetProviderName())
Output:

Found 3 providers.
The provider for google is a version 2.0 provider named GOOGLE.
The provider for facebook is a version 2.0 provider named FACEBOOK.
The provider for twitter is a version 1.0 provider named TWITTER.

func ConfigureProvidersFromYAML

func ConfigureProvidersFromYAML(fileReader io.Reader, callbackURL string) (map[string]OAuthServiceProvider, error)

ConfigureProvidersFromYAML configures a map of providers using a YAML file.

Example
yamlString := `GOOGLE:
  OAuthVersion: 2.0
  AuthURL:      https://accounts.google.com/o/oauth2/auth
  TokenURL:     https://accounts.google.com/o/oauth2/token
  UserInfoURL:  https://www.googleapis.com/oauth2/v2/userinfo
  ClientID:     abcxyz
  ClientSecret: 123098abcxyz
  Scopes:
    - https://www.googleapis.com/auth/userinfo.profile
    - https://www.googleapis.com/auth/userinfo.email

FACEBOOK:
  OAuthVersion: 2.0
  AuthURL:      https://www.facebook.com/dialog/oauth
  TokenURL:     https://graph.facebook.com/oauth/access_token
  UserInfoURL:  https://graph.facebook.com/me?fields=id,first_name,middle_name,last_name,email,picture
  ClientID:     abcxyz
  ClientSecret: 123098abcxyz
  Scopes:
    - email
    - public_profile

TWITTER:
  OAuthVersion:     1.0
  AuthURL:          https://api.twitter.com/oauth/authorize
  TokenURL:         https://api.twitter.com/oauth/access_token
  UserInfoURL:      https://api.twitter.com/1.1/account/verify_credentials.json
  RequestTokenURL:  https://api.twitter.com/oauth/request_token
  ClientID:         abcxyz
  ClientSecret:     123098abcxyz`

reader := strings.NewReader(yamlString)

providers, err := ConfigureProvidersFromYAML(reader, "http://myhost/oauth/callback/%v")
if err != nil {
	fmt.Println(err.Error())
}

fmt.Printf("Found %d providers.\n", len(providers))
fmt.Printf("The provider for %s is a version %s provider named %s.\n", "google",
	providers["google"].GetOAuthVersion(), providers["google"].GetProviderName())
fmt.Printf("The provider for %s is a version %s provider named %s.\n", "facebook",
	providers["facebook"].GetOAuthVersion(), providers["facebook"].GetProviderName())
fmt.Printf("The provider for %s is a version %s provider named %s.\n", "twitter",
	providers["twitter"].GetOAuthVersion(), providers["twitter"].GetProviderName())
Output:

Found 3 providers.
The provider for google is a version 2.0 provider named GOOGLE.
The provider for facebook is a version 2.0 provider named FACEBOOK.
The provider for twitter is a version 1.0 provider named TWITTER.

Types

type OAuth1ServiceProvider

type OAuth1ServiceProvider struct {
	// contains filtered or unexported fields
}

OAuth1ServiceProvider is an implementation of the OAuthServiceProvider interface for use in OAuth Version 1.0 authentication.

func (*OAuth1ServiceProvider) GetOAuthVersion

func (provider *OAuth1ServiceProvider) GetOAuthVersion() string

GetOAuthVersion gets the version of OAuth implemented by this provider.

func (*OAuth1ServiceProvider) GetProviderName

func (provider *OAuth1ServiceProvider) GetProviderName() string

GetProviderName gets the name of of the OAuth provider.

func (*OAuth1ServiceProvider) GetRedirectURL

func (provider *OAuth1ServiceProvider) GetRedirectURL() (string, error)

GetRedirectURL is called when the user first requests to authenticate via OAuth. The URL that is returned is the URL that the user should be redirected to in order to supply the provider with credentials. As an example, if the user is attempting to authenticate via Facebook's API, the user would need to be redirected to Facebook's authentication page.

func (*OAuth1ServiceProvider) ProcessResponse

func (provider *OAuth1ServiceProvider) ProcessResponse(request *http.Request) (UserData, error)

ProcessResponse is called after the user has been successfully authenticated. This method will receive a message back from the OAuth provider containing information about the now authenticated user.

type OAuth1ServiceProviderConfig

type OAuth1ServiceProviderConfig struct {

	// ProviderName is the name of the provider (eg: Google)
	ProviderName string

	// ClientID every provider assigns a client id and a secret key.
	ClientID string

	// ClientSecret every provider assigns a client id and a secret key,
	// this is the secret key.
	ClientSecret string

	// AuthURL is the authentication URL.
	AuthURL string

	// TokenURL is the URL that assigns an access token to the user.
	TokenURL string

	// UserInfoVerb is the verb used to request user information. Usually one of "GET" or
	// "POST". Defaults to GET.
	UserInfoVerb string

	// UserInfoURL is the URL to fetch user data from, once the user is authenticated.
	UserInfoURL string

	// RequestTokenVerb is the verb used to fetch the oauth token information. Usually one of
	// "GET" or "POST". Defaults to POST.
	RequestTokenVerb string

	// RequestTokenURL is the URL used to fetch the oauth token.
	RequestTokenURL string

	// AuthTransmissionType is the type of transmission used to transport authentication information.
	// Usually either as query parameters in the Authentication header.
	// Defaults to Header.
	AuthTransmissionType int

	// RedirectURL is the URL where the browser should be sent after authentication.
	// Often this URL is also provider specific
	// (eg: http://myserver.com/oauth/callback/[provider_name]).
	RedirectURL string
}

OAuth1ServiceProviderConfig is a simple struct which can be used to initialize an OAuth1ServiceProvider.

type OAuth2ServiceProvider

type OAuth2ServiceProvider struct {
	// contains filtered or unexported fields
}

OAuth2ServiceProvider is an implementation of the OAuthServiceProvider interface for use in OAuth Version 2.0 authentication.

func (*OAuth2ServiceProvider) GetOAuthVersion

func (provider *OAuth2ServiceProvider) GetOAuthVersion() string

GetOAuthVersion gets the version of OAuth implemented by this provider.

func (*OAuth2ServiceProvider) GetProviderName

func (provider *OAuth2ServiceProvider) GetProviderName() string

GetProviderName gets the name of of the OAuth provider.

func (*OAuth2ServiceProvider) GetRedirectURL

func (provider *OAuth2ServiceProvider) GetRedirectURL() (string, error)

GetRedirectURL is called when the user first requests to authenticate via OAuth. The URL that is returned is the URL that the user should be redirected to in order to supply the provider with credentials. As an example, if the user is attempting to authenticate via Facebook's API, the user would need to be redirected to Facebook's authentication page.

func (*OAuth2ServiceProvider) ProcessResponse

func (provider *OAuth2ServiceProvider) ProcessResponse(request *http.Request) (UserData, error)

ProcessResponse is called after the user has been successfully authenticated. This method will receive a message back from the OAuth provider containing information about the now authenticated user.

type OAuth2ServiceProviderConfig

type OAuth2ServiceProviderConfig struct {

	// ProviderName is the name of the provider (eg: Google)
	ProviderName string

	// ClientID every provider assigns a client id and a secret key.
	ClientID string

	// ClientSecret every provider assigns a client id and a secret key,
	// this is the secret key.
	ClientSecret string

	// AuthURL is the authentication URL.
	AuthURL string

	// TokenURL is the URL that assigns a token to the user.
	TokenURL string

	// UserInfoURL is the URL to fetch user data from, once the user is authenticated.
	UserInfoURL string

	// RedirectURL is the URL where the browser should be sent after authentication.
	// Often this URL is also provider specific
	// (eg: http://myserver.com/oauth/callback/[provider_name]).
	RedirectURL string

	// Scopes are a list of user details requested. Each provider has
	// their own list of scopes.
	Scopes []string
}

OAuth2ServiceProviderConfig is a simple struct which can be used to initialize an OAuth2ServiceProvider.

type OAuthServiceProvider

type OAuthServiceProvider interface {
	// GetRedirectURL is called when the user first requests to authenticate via OAuth.
	// The URL that is returned is the URL that the user should be redirected to in
	// order to supply the provider with credentials. As an example, if the user is
	// attempting to authenticate via Facebook's API, the user would need to be
	// redirected to Facebook's authentication page.
	GetRedirectURL() (string, error)

	// ProcessResponse is called after the user has been successfully authenticated.
	// This method will receive a message back from the OAuth provider containing
	// information about the now authenticated user.
	ProcessResponse(requet *http.Request) (UserData, error)

	// GetOAuthVersion gets the version of OAuth implemented by this provider.
	GetOAuthVersion() string

	// GetProviderName gets the name of of the OAuth provider.
	GetProviderName() string
}

OAuthServiceProvider is the base class for this library. This is where all of the real work is done. Instances of the this class call the methods necessary to perform the authentication proceedures.

Example
googleConf := OAuth2ServiceProviderConfig{
	ProviderName: "GOOGLE",
	ClientID:     os.Getenv("GOOGLE_CLIENT_ID"),
	ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
	AuthURL:      "https://accounts.google.com/o/oauth2/auth",
	TokenURL:     "https://accounts.google.com/o/oauth2/token",
	UserInfoURL:  "https://www.googleapis.com/oauth2/v2/userinfo",
	RedirectURL:  "http://myserver.com/oauth/callback/google",
	Scopes:       []string{"https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"},
}
twitterConf := OAuth1ServiceProviderConfig{
	ProviderName:    "TWITTER",
	ClientID:        os.Getenv("TWITTER_CLIENT_ID"),
	ClientSecret:    os.Getenv("TWITTER_CLIENT_SECRET"),
	AuthURL:         "https://api.twitter.com/oauth/authorize",
	TokenURL:        "https://api.twitter.com/oauth/access_token",
	UserInfoURL:     "https://api.twitter.com/1.1/account/verify_credentials.json",
	RequestTokenURL: "https://api.twitter.com/oauth/request_token",
	RedirectURL:     "http://myserver.com/oauth/callback/twitter",
	// THE FOLLOWING ARE DEFAULT VALUES
	// UserInfoVerb:         OAuthVerbGet,
	// RequestTokenVerb:     OAuthVerbPost,
	// AuthTransmissionType: OAuth1HeaderTransmissionType,
}

googleProvider := NewOAuth2ServiceProvider(googleConf)
twitterProvider := NewOAuth1ServiceProvider(twitterConf)

http.HandleFunc("/homepage", func(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte(`<html><body><h1>HURRAY</h1></body></html>`))
})

// register providers with http handler
http.HandleFunc("/oauth/authenticate/google", func(w http.ResponseWriter, r *http.Request) {
	redirectURL, _ := googleProvider.GetRedirectURL()
	http.Redirect(w, r, redirectURL, 302)
})
http.HandleFunc("/oauth/authenticate/twitter", func(w http.ResponseWriter, r *http.Request) {
	redirectURL, _ := twitterProvider.GetRedirectURL()
	http.Redirect(w, r, redirectURL, 302)
})

// register response handlers
http.HandleFunc("/oauth/callback/google", func(w http.ResponseWriter, r *http.Request) {
	userData, err := googleProvider.ProcessResponse(r)
	if err != nil {
		http.Error(w, err.Error(), 500)
	} else {
		var sessionID string
		log.Printf("Found user %v", userData.String())
		// create a user session
		// redirect user to new page with a session id
		http.Redirect(w, r, "/homepage?sessionID="+url.QueryEscape(sessionID), 302)
	}
})
http.HandleFunc("/oauth/callback/twitter", func(w http.ResponseWriter, r *http.Request) {
	userData, err := twitterProvider.ProcessResponse(r)
	if err != nil {
		http.Error(w, err.Error(), 500)
	} else {
		var sessionID string
		log.Printf("Found user %v", userData.String())
		// create a user session
		// redirect user to new page with a session id
		http.Redirect(w, r, "/homepage?sessionID="+url.QueryEscape(sessionID), 302)
	}
})
http.ListenAndServe(":9000", nil)
Output:

func NewOAuth1ServiceProvider

func NewOAuth1ServiceProvider(config OAuth1ServiceProviderConfig) OAuthServiceProvider

NewOAuth1ServiceProvider initializes a new OAuth 2.0 service provider.

func NewOAuth2ServiceProvider

func NewOAuth2ServiceProvider(config OAuth2ServiceProviderConfig) OAuthServiceProvider

NewOAuth2ServiceProvider initializes a new OAuth 2.0 service provider.

type UserData

type UserData struct {
	UserID         string
	Email          string
	FullName       string
	GivenName      string
	FamilyName     string
	ScreenName     string
	PhotoURL       string
	OAuthProvider  string
	OAuthVersion   string
	OAuthToken     string
	OAuthTokenType string
}

UserData is a wrapper for the output of the authorization process. The UserData struct will have as much information about the user as this service can provide. This means that not all properties of this struct will be set.

func (UserData) String

func (u UserData) String() string

String prints the formatted contents of UserData.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL