func (a *algoHMAC) ValidateMethod(token *jwt.Token) bool {
	_, ok := token.Method.(*jwt.SigningMethodHMAC)
	return ok
}
ValidateMethod validates method of token
package jwts
import (
	"crypto/rsa"
	"io/ioutil"
	"github.com/dgrijalva/jwt-go"
	"github.com/pkg/errors"
)
type JWTAlgo string
const (
	AlgoHMAC JWTAlgo = "hmac"
	AlgoRSA JWTAlgo = "rsa"
)
type CustomClaims struct {
	Option string `json:"option"`
	jwt.StandardClaims
}
type JWTer interface {
	CreateBasicToken(t int64, clientID, userName string) (string, error)
	CreateCustomToken(t int64, clientID, userName, option string) (string, error)
	ValidateToken(tokenString string) error
	ValidateTokenWithClaim(tokenString, clientID, userName string) error
	ValidateTokenWithCustomClaim(tokenString, clientID, userName, option string) error
}
type jwtee struct {
	audience string
	SigAlgoer
}
func NewJWT(audience string, sigAlgoer SigAlgoer) JWTer {
	return &jwtee{
		audience:  audience,
		SigAlgoer: sigAlgoer,
	}
}
func (j *jwtee) CreateBasicToken(t int64, clientID, userName string) (string, error) {
	token := jwt.NewWithClaims(
		j.SigAlgoer.GetMethod(),
		j.getClaims(t, clientID, userName),
	)
	return j.SigAlgoer.SignedString(token)
}
func (j *jwtee) CreateCustomToken(t int64, clientID, userName, option string) (string, error) {
	claims := &CustomClaims{
		option,
		j.getClaims(t, clientID, userName),
	}
	token := jwt.NewWithClaims(j.SigAlgoer.GetMethod(), claims)
	return j.SigAlgoer.SignedString(token)
}
func (j *jwtee) getClaims(t int64, clientID, userName string) jwt.StandardClaims {
	claims := jwt.StandardClaims{
		Audience: j.audience,
		ExpiresAt: t,
		Issuer:    clientID,
		Subject:   userName,
	}
	return claims
}
func (j *jwtee) keyFunc(token *jwt.Token) (interface{}, error) {
	if isValid := j.SigAlgoer.ValidateMethod(token); !isValid {
		return nil, errors.Errorf("unexpected signing method: %v", token.Header["alg"])
	}
	return j.SigAlgoer.GetKey(), nil
}
func (j *jwtee) ValidateToken(tokenString string) error {
	token, err := jwt.Parse(tokenString, j.keyFunc)
	if err != nil {
		return err
	}
	if !token.Valid {
		return errors.New("token is invalid")
	}
	return nil
}
func (j *jwtee) ValidateTokenWithClaim(tokenString, clientID, userName string) error {
	token, err := jwt.ParseWithClaims(tokenString, &jwt.StandardClaims{}, j.keyFunc)
	if err != nil {
		return err
	}
	if !token.Valid {
		return errors.New("token is invalid")
	}
	claims, ok := token.Claims.(*jwt.StandardClaims)
	if !ok {
		return errors.New("fail to validate claim: claims can't be retrieved")
	}
	if claims.Issuer != clientID {
		return errors.New("fail to validate claim: issuer is invalid")
	}
	if claims.Subject != userName {
		return errors.New("fail to validate claim: subject is invalid")
	}
	return nil
}
func (j *jwtee) ValidateTokenWithCustomClaim(tokenString, clientID, userName, option string) error {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, j.keyFunc)
	if err != nil {
		return err
	}
	if !token.Valid {
		return errors.New("token is invalid")
	}
	claims, ok := token.Claims.(*CustomClaims)
	if !ok {
		return errors.New("fail to validate claim: claims data can't be retrieved")
	} else if claims.Issuer != clientID {
		return errors.New("fail to validate claim: issuer is invalid")
	} else if claims.Subject != userName {
		return errors.New("fail to validate claim: subject is invalid")
	} else if claims.Option != option {
		return errors.New("fail to validate claim: option is invalid")
	}
	return nil
}
type SigAlgoer interface {
	GetMethod() jwt.SigningMethod
	SignedString(token *jwt.Token) (string, error)
	ValidateMethod(token *jwt.Token) bool
	GetKey() interface{}
}
type algoHMAC struct {
	encrypted JWTAlgo
	method    jwt.SigningMethod
	secret    string
}
func NewHMAC(secret string) SigAlgoer {
	return &algoHMAC{
		encrypted: AlgoHMAC,
		method:    jwt.SigningMethodHS256,
		secret:    secret,
	}
}
func (a *algoHMAC) GetMethod() jwt.SigningMethod {
	return a.method
}
func (a *algoHMAC) SignedString(token *jwt.Token) (string, error) {
	return token.SignedString([]byte(a.secret))
}