func (a Auth) AuthorizeAPI(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		tk, err := a.verify(r)
		if err != nil {
			http.Error(w, fmt.Sprintf(`{"error": "unauthorized, "reason": "%v"}`, err), http.StatusUnauthorized)
			return
		}
		if a.enabled() {
			claims := tk.Claims.(jwt.MapClaims)
			if expired := (getNumberFromJSON(claims["exp"]) - time.Now().Unix()) <= 0; expired {
				RenderError(errors.New("token expired"), http.StatusUnauthorized, w, r)
				return
			}
			rawClaimsSdkKeys, ok := claims["sdk_keys"].([]interface{})
			if !ok {
				RenderError(errors.New("invalid claims: sdk_keys not found, or have the wrong type"), http.StatusUnauthorized, w, r)
				return
			}
			sdkKeyFromHeader := r.Header.Get(OptlySDKHeader)
			foundMatchingSdkKey := false
			for _, rawSdkKey := range rawClaimsSdkKeys {
				sdkKey, ok := rawSdkKey.(string)
				if !ok {
					GetLogger(r).Warn().Msgf("Non-string value in token claims sdk_keys: %v", sdkKey)
					continue
				}
				if sdkKey == sdkKeyFromHeader {
					foundMatchingSdkKey = true
					break
				}
			}
			if !foundMatchingSdkKey {
				RenderError(errors.New("SDK key given in X-Optimizely-Sdk-Key header was not found in the SDK keys in this token's claims"), http.StatusUnauthorized, w, r)
				return
			}
		}
		next.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
AuthorizeAPI is middleware for auth api
package middleware
import (
	"errors"
	"fmt"
	"net/http"
	"strings"
	"sync"
	"time"
	"github.com/optimizely/agent/config"
	"github.com/optimizely/agent/pkg/jwtauth"
	"github.com/dgrijalva/jwt-go"
	"github.com/lestrrat-go/jwx/jwk"
	"github.com/rs/zerolog/log"
)
func getNumberFromJSON(val interface{}) int64 {
	switch v := val.(type) {
	case int64:
		return v
	case float64:
		return int64(v)
	}
	return 0
}
type NoAuth struct{}
func (NoAuth) CheckToken(string) (*jwt.Token, error) {
	return nil, nil
}
type Auth struct {
	Verifier
}
type Verifier interface {
	CheckToken(string) (*jwt.Token, error)
}
type JWTVerifier struct {
	secretKeys [][]byte
}
func NewJWTVerifier(secretKeys [][]byte) *JWTVerifier {
	return &JWTVerifier{secretKeys: secretKeys}
}
func (c JWTVerifier) CheckToken(token string) (*jwt.Token, error) {
	if token == "" {
		return nil, errors.New("empty token")
	}
	lastSeenErr := errors.New("invalid token")
	for _, secretKey := range c.secretKeys {
		secretKey := secretKey
		tk, currentErr := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, errors.New("unexpected signing method")
			}
			return secretKey, nil
		})
		lastSeenErr = currentErr
		if lastSeenErr != nil {
			continue
		}
		if !tk.Valid {
			lastSeenErr = errors.New("invalid token")
			continue
		}
		return tk, nil
	}
	return nil, lastSeenErr
}
type JWTVerifierURL struct {
	jwksURL string
	parser   *jwt.Parser
	jwksKeys *jwk.Set
	jwksLock sync.RWMutex
}
func (c *JWTVerifierURL) startTicker(ticker time.Duration) {
	tick := time.NewTicker(ticker)
	defer tick.Stop()
	for range tick.C {
		err := c.updateKeySet()
		if err != nil {
			log.Warn().Err(err).Msg("unable to update JWKS key set")
		}
	}
}
func (c *JWTVerifierURL) updateKeySet() error {
	c.jwksLock.Lock()
	defer c.jwksLock.Unlock()
	set, err := jwk.Fetch(c.jwksURL)
	if err != nil {
		return err
	}
	c.jwksKeys = set
	return nil
}
func (c *JWTVerifierURL) getKeySet() *jwk.Set {
	c.jwksLock.RLock()
	defer c.jwksLock.RUnlock()
	return c.jwksKeys
}
func NewJWTVerifierURL(jwksURL string, updateInterval time.Duration) *JWTVerifierURL {
	http.DefaultClient = &http.Client{Timeout: 10 * time.Second}
	jwtVerifierURL := JWTVerifierURL{jwksURL: jwksURL, parser: new(jwt.Parser)}
	err := jwtVerifierURL.updateKeySet()
	if err != nil {
		log.Error().Err(err).Msg("unable to fetch key set")
		return nil
	}
	go jwtVerifierURL.startTicker(updateInterval)
	return &jwtVerifierURL
}
func (c *JWTVerifierURL) CheckToken(token string) (tk *jwt.Token, err error) {
	if token == "" {
		return nil, errors.New("empty token")
	}
	tk, err = c.parser.Parse(token, func(token *jwt.Token) (interface{}, error) {
		set := c.getKeySet()
		if set == nil {
			return nil, fmt.Errorf("unable to update key set")
		}
		keyID, ok := token.Header["kid"].(string)
		if !ok {
			return nil, errors.New("expecting JWT header to have string kid")
		}
		if key := set.LookupKeyID(keyID); len(key) == 1 {
			return key[0].Materialize()
		}
		return nil, fmt.Errorf("unable to find key %q", keyID)
	})
	if err != nil {
		return nil, err
	}
	if !tk.Valid {
		return nil, errors.New("invalid token")
	}
	return tk, nil
}
func (a Auth) verify(r *http.Request) (*jwt.Token, error) {
	var token string
	if values, ok := r.Header["Auth"]; ok && len(values) > 0 {
		token = values[0]
	}
	if values, ok := r.Header["Jwt"]; ok && len(values) > 0 {
		token = values[0]
	}
	if values, ok := r.Header["Authorization"]; ok && len(values) > 0 {
		value := values[0]
		for _, key := range []string{"JWT", "Bearer"} {
			token = strings.TrimSpace(strings.TrimLeft(value, key))
		}
	}
	return a.CheckToken(token)
}
func (a Auth) enabled() bool {
	if _, ok := a.Verifier.(NoAuth); ok {
		return false
	}
	return true
}
func (a Auth) AuthorizeAdmin(next http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		tk, err := a.verify(r)
		if err != nil {
			RenderError(err, http.StatusUnauthorized, w, r)
			return
		}
		if a.enabled() {
			claims := tk.Claims.(jwt.MapClaims)
			if expired := (getNumberFromJSON(claims["exp"]) - time.Now().Unix()) <= 0; expired {
				RenderError(errors.New("token expired"), http.StatusUnauthorized, w, r)
				return
			}
			if adminFlag, ok := claims["admin"].(bool); !ok || !adminFlag {
				RenderError(errors.New("admin flag not set"), http.StatusUnauthorized, w, r)
				return
			}
		}
		next.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}