func (a *Authenticator) AdminOnly(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		user, err := token.GetUserInfo(r)
		if err != nil {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		if !user.IsAdmin() {
			http.Error(w, "Access denied", http.StatusForbidden)
			return
		}
		next.ServeHTTP(w, r)
	}
	return a.auth(true)(http.HandlerFunc(fn))  
}
AdminOnly middleware allows access for admins only
this handler internally wrapped with auth(true) to avoid situation if AdminOnly defined without prior Auth
package middleware
import (
	"crypto/subtle"
	"net/http"
	"strings"
	"github.com/pkg/errors"
	"github.com/go-pkgz/auth/logger"
	"github.com/go-pkgz/auth/provider"
	"github.com/go-pkgz/auth/token"
)
type Authenticator struct {
	logger.L
	JWTService       TokenService
	Providers        []provider.Service
	Validator        token.Validator
	AdminPasswd      string
	BasicAuthChecker BasicAuthFunc
	RefreshCache     RefreshCache
}
type RefreshCache interface {
	Get(key interface{}) (value interface{}, ok bool)
	Set(key, value interface{})
}
type TokenService interface {
	Parse(tokenString string) (claims token.Claims, err error)
	Set(w http.ResponseWriter, claims token.Claims) (token.Claims, error)
	Get(r *http.Request) (claims token.Claims, token string, err error)
	IsExpired(claims token.Claims) bool
	Reset(w http.ResponseWriter)
}
type BasicAuthFunc func(user, passwd string) (ok bool, userInfo token.User, err error)
var adminUser = token.User{
	ID:   "admin",
	Name: "admin",
	Attributes: map[string]interface{}{
		"admin": true,
	},
}
func (a *Authenticator) Auth(next http.Handler) http.Handler {
	return a.auth(true)(next)
}
func (a *Authenticator) Trace(next http.Handler) http.Handler {
	return a.auth(false)(next)
}
func (a *Authenticator) auth(reqAuth bool) func(http.Handler) http.Handler {
	onError := func(h http.Handler, w http.ResponseWriter, r *http.Request, err error) {
		if !reqAuth {  
			h.ServeHTTP(w, r)
			return
		}
		a.Logf("[DEBUG] auth failed, %v", err)
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
	}
	f := func(h http.Handler) http.Handler {
		fn := func(w http.ResponseWriter, r *http.Request) {
			if a.BasicAuthChecker == nil && a.basicAdminUser(r) {
				r = token.SetUserInfo(r, adminUser)
				h.ServeHTTP(w, r)
				return
			}
			if a.BasicAuthChecker != nil {
				if user, passwd, isBasicAuth := r.BasicAuth(); isBasicAuth {
					ok, userInfo, err := a.BasicAuthChecker(user, passwd)
					if err != nil {
						onError(h, w, r, errors.Wrap(err, "basic auth check failed"))
						return
					}
					if !ok {
						onError(h, w, r, errors.Wrap(err, "credentials are wrong for basic auth"))
						return
					}
					r = token.SetUserInfo(r, userInfo)  
					h.ServeHTTP(w, r)
					return
				}
			}
			claims, tkn, err := a.JWTService.Get(r)
			if err != nil {
				onError(h, w, r, errors.Wrap(err, "can't get token"))
				return
			}
			if claims.Handshake != nil {  
				onError(h, w, r, errors.New("invalid kind of token"))
				return
			}
			if claims.User == nil {
				onError(h, w, r, errors.New("no user info presented in the claim"))
				return
			}
			if claims.User != nil {  
				if a.Validator != nil && !a.Validator.Validate(tkn, claims) {
					onError(h, w, r, errors.Errorf("user %s/%s blocked", claims.User.Name, claims.User.ID))
					a.JWTService.Reset(w)
					return
				}
				if a.JWTService.IsExpired(claims) {
					if claims, err = a.refreshExpiredToken(w, claims, tkn); err != nil {
						a.JWTService.Reset(w)
						onError(h, w, r, errors.Wrap(err, "can't refresh token"))
						return
					}
				}
				r = token.SetUserInfo(r, *claims.User)  
			}
			h.ServeHTTP(w, r)
		}
		return http.HandlerFunc(fn)
	}
	return f
}
func (a *Authenticator) refreshExpiredToken(w http.ResponseWriter, claims token.Claims, tkn string) (token.Claims, error) {
	if a.RefreshCache != nil {
		if c, ok := a.RefreshCache.Get(tkn); ok {
			return c.(token.Claims), nil
		}
	}
	claims.ExpiresAt = 0                   
	c, err := a.JWTService.Set(w, claims)  
	if err != nil {
		return token.Claims{}, err
	}
	if a.RefreshCache != nil {
		a.RefreshCache.Set(tkn, c)
	}
	a.Logf("[DEBUG] token refreshed for %+v", claims.User)
	return c, nil
}