func (s *Service) TokenService() *token.Service {
	return s.jwtService
}
TokenService returns token.Service
package auth
import (
	"fmt"
	"net/http"
	"strings"
	"time"
	"github.com/go-pkgz/rest"
	"github.com/pkg/errors"
	"github.com/go-pkgz/auth/avatar"
	"github.com/go-pkgz/auth/logger"
	"github.com/go-pkgz/auth/middleware"
	"github.com/go-pkgz/auth/provider"
	"github.com/go-pkgz/auth/token"
)
type Client struct {
	Cid     string
	Csecret string
}
type Service struct {
	logger         logger.L
	opts           Opts
	jwtService     *token.Service
	providers      []provider.Service
	authMiddleware middleware.Authenticator
	avatarProxy    *avatar.Proxy
	issuer         string
	useGravatar    bool
}
type Opts struct {
	SecretReader   token.Secret         
	ClaimsUpd      token.ClaimsUpdater  
	SecureCookies  bool                 
	TokenDuration  time.Duration        
	CookieDuration time.Duration        
	DisableXSRF bool  
	DisableIAT  bool  
	JWTCookieName   string         
	JWTCookieDomain string         
	JWTHeaderKey    string         
	XSRFCookieName  string         
	XSRFHeaderKey   string         
	JWTQuery        string         
	SendJWTHeader   bool           
	SameSiteCookie  http.SameSite  
	Issuer string  
	URL       string           
	Validator token.Validator  
	AvatarStore       avatar.Store  
	AvatarResizeLimit int           
	AvatarRoutePath   string        
	UseGravatar       bool          
	AdminPasswd      string                    
	BasicAuthChecker middleware.BasicAuthFunc  
	AudienceReader   token.Audience            
	AudSecrets       bool                      
	Logger           logger.L                  
	RefreshCache     middleware.RefreshCache   
}
func NewService(opts Opts) (res *Service) {
	res = &Service{
		opts:   opts,
		logger: opts.Logger,
		authMiddleware: middleware.Authenticator{
			Validator:        opts.Validator,
			AdminPasswd:      opts.AdminPasswd,
			BasicAuthChecker: opts.BasicAuthChecker,
			RefreshCache:     opts.RefreshCache,
		},
		issuer:      opts.Issuer,
		useGravatar: opts.UseGravatar,
	}
	if opts.Issuer == "" {
		res.issuer = "go-pkgz/auth"
	}
	if opts.Logger == nil {
		res.logger = logger.NoOp
	}
	jwtService := token.NewService(token.Opts{
		SecretReader:    opts.SecretReader,
		ClaimsUpd:       opts.ClaimsUpd,
		SecureCookies:   opts.SecureCookies,
		TokenDuration:   opts.TokenDuration,
		CookieDuration:  opts.CookieDuration,
		DisableXSRF:     opts.DisableXSRF,
		DisableIAT:      opts.DisableIAT,
		JWTCookieName:   opts.JWTCookieName,
		JWTCookieDomain: opts.JWTCookieDomain,
		JWTHeaderKey:    opts.JWTHeaderKey,
		XSRFCookieName:  opts.XSRFCookieName,
		XSRFHeaderKey:   opts.XSRFHeaderKey,
		SendJWTHeader:   opts.SendJWTHeader,
		JWTQuery:        opts.JWTQuery,
		Issuer:          res.issuer,
		AudienceReader:  opts.AudienceReader,
		AudSecrets:      opts.AudSecrets,
		SameSite:        opts.SameSiteCookie,
	})
	if opts.SecretReader == nil {
		jwtService.SecretReader = token.SecretFunc(func(string) (string, error) {
			return "", errors.New("secrets reader not available")
		})
		res.logger.Logf("[WARN] no secret reader defined")
	}
	res.jwtService = jwtService
	res.authMiddleware.JWTService = jwtService
	res.authMiddleware.L = res.logger
	if opts.AvatarStore != nil {
		res.avatarProxy = &avatar.Proxy{
			Store:       opts.AvatarStore,
			URL:         opts.URL,
			RoutePath:   opts.AvatarRoutePath,
			ResizeLimit: opts.AvatarResizeLimit,
			L:           res.logger,
		}
		if res.avatarProxy.RoutePath == "" {
			res.avatarProxy.RoutePath = "/avatar"
		}
	}
	return res
}
func (s *Service) Handlers() (authHandler, avatarHandler http.Handler) {
	ah := func(w http.ResponseWriter, r *http.Request) {
		elems := strings.Split(r.URL.Path, "/")
		if len(elems) < 2 {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		if elems[len(elems)-1] == "list" {
			list := []string{}
			for _, p := range s.providers {
				list = append(list, p.Name())
			}
			rest.RenderJSON(w, list)
			return
		}
		if elems[len(elems)-1] == "logout" {
			if len(s.providers) == 0 {
				w.WriteHeader(http.StatusBadRequest)
				rest.RenderJSON(w, rest.JSON{"error": "provides not defined"})
				return
			}
			s.providers[0].Handler(w, r)
			return
		}
		if elems[len(elems)-1] == "user" {
			claims, _, err := s.jwtService.Get(r)
			if err != nil {
				w.WriteHeader(http.StatusUnauthorized)
				rest.RenderJSON(w, rest.JSON{"error": err.Error()})
				return
			}
			rest.RenderJSON(w, claims.User)
			return
		}
		provName := elems[len(elems)-2]
		p, err := s.Provider(provName)
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			rest.RenderJSON(w, rest.JSON{"error": fmt.Sprintf("provider %s not supported", provName)})
			return
		}
		p.Handler(w, r)
	}
	return http.HandlerFunc(ah), http.HandlerFunc(s.avatarProxy.Handler)
}
func (s *Service) Middleware() middleware.Authenticator {
	return s.authMiddleware
}
func (s *Service) AddProvider(name, cid, csecret string) {
	p := provider.Params{
		URL:         s.opts.URL,
		JwtService:  s.jwtService,
		Issuer:      s.issuer,
		AvatarSaver: s.avatarProxy,
		Cid:         cid,
		Csecret:     csecret,
		L:           s.logger,
	}
	switch strings.ToLower(name) {
	case "github":
		s.providers = append(s.providers, provider.NewService(provider.NewGithub(p)))
	case "google":
		s.providers = append(s.providers, provider.NewService(provider.NewGoogle(p)))
	case "facebook":
		s.providers = append(s.providers, provider.NewService(provider.NewFacebook(p)))
	case "yandex":
		s.providers = append(s.providers, provider.NewService(provider.NewYandex(p)))
	case "battlenet":
		s.providers = append(s.providers, provider.NewService(provider.NewBattlenet(p)))
	case "microsoft":
		s.providers = append(s.providers, provider.NewService(provider.NewMicrosoft(p)))
	case "twitter":
		s.providers = append(s.providers, provider.NewService(provider.NewTwitter(p)))
	case "patreon":
		s.providers = append(s.providers, provider.NewService(provider.NewPatreon(p)))
	case "dev":
		s.providers = append(s.providers, provider.NewService(provider.NewDev(p)))
	default:
		return
	}
	s.authMiddleware.Providers = s.providers
}
func (s *Service) AddDevProvider(port int) {
	p := provider.Params{
		URL:         s.opts.URL,
		JwtService:  s.jwtService,
		Issuer:      s.issuer,
		AvatarSaver: s.avatarProxy,
		L:           s.logger,
		Port:        port,
	}
	s.providers = append(s.providers, provider.NewService(provider.NewDev(p)))
}
func (s *Service) AddAppleProvider(appleConfig provider.AppleConfig, privKeyLoader provider.PrivateKeyLoaderInterface) error {
	p := provider.Params{
		URL:         s.opts.URL,
		JwtService:  s.jwtService,
		Issuer:      s.issuer,
		AvatarSaver: s.avatarProxy,
		L:           s.logger,
	}
	appleProvider, err := provider.NewApple(p, appleConfig, privKeyLoader)
	if err != nil {
		return errors.Wrap(err, "an AppleProvider creating failed")
	}
	s.providers = append(s.providers, provider.NewService(appleProvider))
	return nil
}
func (s *Service) AddCustomProvider(name string, client Client, copts provider.CustomHandlerOpt) {
	p := provider.Params{
		URL:         s.opts.URL,
		JwtService:  s.jwtService,
		Issuer:      s.issuer,
		AvatarSaver: s.avatarProxy,
		Cid:         client.Cid,
		Csecret:     client.Csecret,
		L:           s.logger,
	}
	s.providers = append(s.providers, provider.NewService(provider.NewCustom(name, p, copts)))
	s.authMiddleware.Providers = s.providers
}
func (s *Service) AddDirectProvider(name string, credChecker provider.CredChecker) {
	dh := provider.DirectHandler{
		L:            s.logger,
		ProviderName: name,
		Issuer:       s.issuer,
		TokenService: s.jwtService,
		CredChecker:  credChecker,
		AvatarSaver:  s.avatarProxy,
	}
	s.providers = append(s.providers, provider.NewService(dh))
	s.authMiddleware.Providers = s.providers
}
func (s *Service) AddDirectProviderWithUserIDFunc(name string, credChecker provider.CredChecker, ufn provider.UserIDFunc) {
	dh := provider.DirectHandler{
		L:            s.logger,
		ProviderName: name,
		Issuer:       s.issuer,
		TokenService: s.jwtService,
		CredChecker:  credChecker,
		AvatarSaver:  s.avatarProxy,
		UserIDFunc:   ufn,
	}
	s.providers = append(s.providers, provider.NewService(dh))
	s.authMiddleware.Providers = s.providers
}
func (s *Service) AddVerifProvider(name, msgTmpl string, sender provider.Sender) {
	dh := provider.VerifyHandler{
		L:            s.logger,
		ProviderName: name,
		Issuer:       s.issuer,
		TokenService: s.jwtService,
		AvatarSaver:  s.avatarProxy,
		Sender:       sender,
		Template:     msgTmpl,
		UseGravatar:  s.useGravatar,
	}
	s.providers = append(s.providers, provider.NewService(dh))
	s.authMiddleware.Providers = s.providers
}
func (s *Service) AddCustomHandler(handler provider.Provider) {
	s.providers = append(s.providers, provider.NewService(handler))
	s.authMiddleware.Providers = s.providers
}
func (s *Service) DevAuth() (*provider.DevAuthServer, error) {
	p, err := s.Provider("dev")  
	if err != nil {
		return nil, errors.Wrap(err, "dev provider not registered")
	}
	return &provider.DevAuthServer{Provider: p.Provider.(provider.Oauth2Handler), L: s.logger}, nil
}
func (s *Service) Provider(name string) (provider.Service, error) {
	for _, p := range s.providers {
		if p.Name() == name {
			return p, nil
		}
	}
	return provider.Service{}, errors.Errorf("provider %s not found", name)
}
func (s *Service) Providers() []provider.Service {
	return s.providers
}