package auth import ( "encoding/base64" "errors" "strings" "time" "github.com/golang-jwt/jwt/v4" "github.com/google/uuid" ) // JWTAccessClaims jwt claims type JWTAccessClaims struct { jwt.RegisteredClaims } // Valid claims verification func (a *JWTAccessClaims) Valid() error { if a.ExpiresAt.Before(time.Now()) { return ErrInvalidAccessToken } return nil } // NewJWTAccessGenerate create to generate the jwt access token instance func NewJWTAccessGenerate(key []byte, method jwt.SigningMethod) *JWTAccessGenerate { return &JWTAccessGenerate{ SignedKey: key, SignedMethod: method, } } // JWTAccessGenerate generate the jwt access token type JWTAccessGenerate struct { SignedKey []byte SignedMethod jwt.SigningMethod } // Token based on the UUID generated token func (a *JWTAccessGenerate) Token(data *GenerateBasic, isGenRefresh bool) (string, string, error) { claims := &JWTAccessClaims{ RegisteredClaims: jwt.RegisteredClaims{ Issuer: "BvBeJ", Subject: data.UserID, ExpiresAt: jwt.NewNumericDate(data.TokenInfo.GetAccessCreateAt().Add(data.TokenInfo.GetAccessExpiresIn())), }, } token := jwt.NewWithClaims(a.SignedMethod, claims) var key any if a.isEs() { v, err := jwt.ParseECPrivateKeyFromPEM(a.SignedKey) if err != nil { return "", "", err } key = v } else if a.isRsOrPS() { v, err := jwt.ParseRSAPrivateKeyFromPEM(a.SignedKey) if err != nil { return "", "", err } key = v } else if a.isHs() { key = a.SignedKey } else { return "", "", errors.New("unsupported sign method") } access, err := token.SignedString(key) if err != nil { return "", "", err } refresh := "" if isGenRefresh { t := uuid.NewSHA1(uuid.Must(uuid.NewRandom()), []byte(access)).String() refresh = base64.URLEncoding.EncodeToString([]byte(t)) refresh = strings.ToUpper(strings.TrimRight(refresh, "=")) } return access, refresh, nil } func (a *JWTAccessGenerate) isEs() bool { return strings.HasPrefix(a.SignedMethod.Alg(), "ES") } func (a *JWTAccessGenerate) isRsOrPS() bool { isRs := strings.HasPrefix(a.SignedMethod.Alg(), "RS") isPs := strings.HasPrefix(a.SignedMethod.Alg(), "PS") return isRs || isPs } func (a *JWTAccessGenerate) isHs() bool { return strings.HasPrefix(a.SignedMethod.Alg(), "HS") }