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
}
ValidateTokenWithCustomClaim validates token by clientID and userName and option
may be too strict to check
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
}