Documentation ¶
Overview ¶
Package oauth is the OAuth2 authentication driver for github.com/hiendv/gate. It uses client implementations, not OAuth servers e.g. Google, Facebook, etc.
Example ¶
var auth gate.Auth roles := []fixtures.Role{ { ID: fixtures.RandomString(8), Abilities: []fixtures.Ability{ {Action: "GET", Object: "/api/v1/*"}, {Action: "POST", Object: "/api/v1/users*"}, }, }, { ID: fixtures.RandomString(8), Abilities: []fixtures.Ability{ {Action: "GET", Object: "*"}, }, }, { ID: fixtures.RandomString(8), Abilities: []fixtures.Ability{ {Action: "POST", Object: "/api/v1/posts*"}, }, }, } users := []fixtures.User{ { ID: "id", Email: "foo@local", Roles: []string{ roles[0].ID, roles[1].ID, }, }, { ID: "id2", Email: "bar@local", Roles: []string{}, }, { ID: "id3", Email: "nobody@local", Roles: []string{}, }, } roleService := fixtures.NewMyRoleService(roles) userService := fixtures.NewMyUserService(users) tokenService := fixtures.NewMyTokenService(nil) driver = New( NewGoogleConfig( gate.NewConfig("jwt-secret", "jwt-secret", time.Hour*1, false), "google-client-id", "google-client-secret", "http://localhost:8080", ), GoogleStatelessHandler, dependency.NewContainer(userService, tokenService, roleService), ) // Mocking driver.setProvider(fixtures.OAuthProvider{ map[string]gate.HasEmail{ "code-token": GoogleUser{ Email: "foo@local", EmailVerified: true, }, }, }) auth = driver if auth == nil { fmt.Println("auth should not be nil") return } user, err := auth.Login(map[string]string{"code": "code"}) if err != nil { fmt.Println(err) return } fmt.Printf("Tokens: %d\n", tokenService.Count()) jwt, err := auth.IssueJWT(user) if err != nil { fmt.Println(err) return } fmt.Printf("Tokens: %d\n", tokenService.Count()) parsedUser, err := auth.Authenticate(jwt.Value) if err != nil { fmt.Println(err) return } fmt.Printf("%s:%s - %v\n", parsedUser.GetID(), parsedUser.GetEmail(), err) err = auth.Authorize(parsedUser, "GET", "/api/v1/users") fmt.Printf("%v\n", err) err = auth.Authorize(parsedUser, "GET", "/api/v1/posts") fmt.Printf("%v\n", err) err = auth.Authorize(parsedUser, "POST", "/api/v1/users") fmt.Printf("%v\n", err) err = auth.Authorize(parsedUser, "POST", "/api/v1/posts") fmt.Printf("%v\n", err)
Output: Tokens: 0 Tokens: 1 id:foo@local - <nil> <nil> <nil> <nil> forbidden
Index ¶
- type Config
- type DefaultProvider
- type Driver
- func (auth Driver) Authenticate(tokenString string) (user gate.User, err error)
- func (auth Driver) Authorize(user gate.User, action, object string) (err error)
- func (auth Driver) GetUserAbilities(user gate.User) (abilities []gate.UserAbility, err error)
- func (auth Driver) GetUserFromJWT(token gate.JWT) (user gate.User, err error)
- func (auth Driver) IssueJWT(user gate.User) (token gate.JWT, err error)
- func (auth Driver) Login(credentials map[string]string) (user gate.User, err error)
- func (auth Driver) LoginURL(state string) (string, error)
- func (auth Driver) ParseJWT(tokenString string) (token gate.JWT, err error)
- func (auth Driver) StoreJWT(token gate.JWT) (err error)
- type GoogleUser
- type LoginFunc
- type Provider
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct { gate.Config ClientID string ClientSecret string Scopes []string Endpoint oauth2.Endpoint RedirectURI string UserAPI string }
Config is the configuration for OAuth authentication
func NewFacebookConfig ¶
NewFacebookConfig is the constructor for OAuth configuration using Facebook API
type DefaultProvider ¶
type DefaultProvider struct {
// contains filtered or unexported fields
}
DefaultProvider is the default OAuth provider
func (DefaultProvider) AuthCodeURL ¶
func (provider DefaultProvider) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string
AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
func (DefaultProvider) Client ¶
func (provider DefaultProvider) Client(ctx context.Context, t *oauth2.Token) internal.HTTPClient
Client returns an HTTP client using the provided token
type Driver ¶
type Driver struct { dependency.Container // contains filtered or unexported fields }
Driver is OAuth authentication
func New ¶
func New(config Config, handler LoginFunc, container dependency.Container) *Driver
New is the constructor for Driver
func (Driver) Authenticate ¶
Authenticate performs the authentication using JWT
Example ¶
users := []fixtures.User{ { ID: "id", Email: "foo@local", Roles: []string{}, }, } userService := fixtures.NewMyUserService(users) tokenService := fixtures.NewMyTokenService(nil) driver := New( NewGoogleConfig( gate.NewConfig("jwt-secret", "jwt-secret", time.Hour*1, true), "google-client-id", "google-client-secret", "http://localhost:8080", ), GoogleStatelessHandler, // Role service is omitted dependency.NewContainer(userService, tokenService, nil), ) if driver == nil { fmt.Println("driver should not be nil") return } user, err := driver.Authenticate("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiaWQiLCJlbWFpbCI6ImZvb0Bsb2NhbCIsInJvbGVzIjpbXX0sImV4cCI6MTYwNTA1MjgwMCwianRpIjoiY2xhaW1zLWlkIiwiaWF0IjoxNjA1MDQ5MjAwfQ.GfDJ1Cl8f7nX6urWV4F2RgXGPXLfwYh9syfghVJ57XY") if err != nil { fmt.Println(err) return } fmt.Printf("%s:%s - %v", user.GetID(), user.GetEmail(), err)
Output: id:foo@local - <nil>
func (Driver) Authorize ¶
Authorize performs the authorization when a given user takes an action on an object using RBAC
func (Driver) GetUserAbilities ¶
GetUserAbilities returns a user's abilities
func (Driver) GetUserFromJWT ¶
GetUserFromJWT returns a user from a given JWT
func (Driver) IssueJWT ¶
IssueJWT issues and stores a JWT for a specific user
Example ¶
var auth gate.Auth users := []fixtures.User{ { ID: "id", Email: "foo@local", Roles: []string{}, }, } userService := fixtures.NewMyUserService(users) tokenService := fixtures.NewMyTokenService(nil) driver = New( NewGoogleConfig( gate.NewConfig("jwt-secret", "jwt-secret", time.Hour*1, false), "google-client-id", "google-client-secret", "http://localhost:8080", ), GoogleStatelessHandler, // Role service is omitted dependency.NewContainer(userService, tokenService, nil), ) // Mocking driver.setProvider(fixtures.OAuthProvider{ map[string]gate.HasEmail{ "code-token": GoogleUser{ Email: "foo@local", EmailVerified: true, }, }, }) auth = driver if auth == nil { fmt.Println("auth should not be nil") return } jwtConfig, err := gate.NewHMACJWTConfig("HS256", driver.config.JWTSigningKey(), driver.config.JWTExpiration(), driver.config.JWTSkipClaimsValidation()) if err != nil { fmt.Println(err) return } mockedJWTService := gate.NewJWTService(jwtConfig) mockedJWTService.Now = func() time.Time { return time.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC) } mockedJWTService.GenerateClaimsID = func() string { return "claims-id" } driver.Container.SetJWTService(mockedJWTService) user, err := auth.Login(map[string]string{"code": "code"}) if err != nil { fmt.Println(err) return } jwt, err := auth.IssueJWT(user) if err != nil { fmt.Println(err) return } fmt.Printf("%s:%s@%s - %v", jwt.ID, jwt.Value, jwt.UserID, err)
Output: claims-id:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiaWQiLCJlbWFpbCI6ImZvb0Bsb2NhbCIsInJvbGVzIjpbXX0sImV4cCI6MTYwNTA1MjgwMCwianRpIjoiY2xhaW1zLWlkIiwiaWF0IjoxNjA1MDQ5MjAwfQ.GfDJ1Cl8f7nX6urWV4F2RgXGPXLfwYh9syfghVJ57XY@id - <nil>
func (Driver) Login ¶
Login resolves OAuth authentication with the given handler and credentials
Example ¶
var auth gate.Auth users := []fixtures.User{ { ID: "id", Email: "foo@local", Roles: []string{}, }, { ID: "id2", Email: "bar@local", Roles: []string{}, }, } userService := fixtures.NewMyUserService(users) driver = New( NewGoogleConfig( gate.NewConfig("jwt-secret", "jwt-secret", time.Hour*1, false), "google-client-id", "google-client-secret", "http://localhost:8080", ), GoogleStatelessHandler, // Token and Role services are omitted dependency.NewContainer(userService, nil, nil), ) // Mocking driver.setProvider(fixtures.OAuthProvider{ map[string]gate.HasEmail{ "code-token": GoogleUser{ Email: "foo@local", EmailVerified: true, }, "code2-token": GoogleUser{ Email: "foo@local", EmailVerified: true, }, "code3-token": GoogleUser{ Email: "bar@local", EmailVerified: true, }, }, }) auth = driver if auth == nil { fmt.Println("auth should not be nil") return } user, err := auth.Login(map[string]string{"code": "code"}) if err != nil { fmt.Println(err) return } fmt.Printf("%s:%s - %v\n", user.GetID(), user.GetEmail(), err) secondUser, err := auth.Login(map[string]string{"code": "code2"}) if err != nil { fmt.Println(err) return } fmt.Printf("%s:%s - %v\n", secondUser.GetID(), secondUser.GetEmail(), err) thirdUser, err := auth.Login(map[string]string{"code": "code3"}) if err != nil { fmt.Println(err) return } fmt.Printf("%s:%s - %v\n", thirdUser.GetID(), thirdUser.GetEmail(), err)
Output: id:foo@local - <nil> id:foo@local - <nil> id2:bar@local - <nil>
type GoogleUser ¶
GoogleUser is the user from Google API
type LoginFunc ¶
LoginFunc is the handler of OAuth authentication
var GoogleStatelessHandler LoginFunc = func(driver Driver, code, state string) (account gate.HasEmail, err error) { token, err := driver.provider.Exchange(context.TODO(), code) if err != nil { return } client := driver.provider.Client(context.TODO(), token) if client == nil { err = errors.New("invalid API client") return } response, err := client.Get(driver.config.UserAPI) if err != nil { return } if response == nil { err = errors.New("invalid API response") return } defer func(response *http.Response) { e := response.Body.Close() if e == nil { return } }(response) var user GoogleUser err = json.NewDecoder(response.Body).Decode(&user) if err != nil { return } account = user return }
GoogleStatelessHandler is the stateless login handler using Google API