package token import ( "errors" "fmt" "time" "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" ) const minSecretKeySize = 32 // JWTMaker is a JSON Web Token maker type JWTMaker struct { secretKey string } // NewJWTMaker creates a new JWTMaker func NewJWTMaker(secretKey string) (Maker, error) { if len(secretKey) < minSecretKeySize { return nil, fmt.Errorf("invalid key size: must be at least %d characters", minSecretKeySize) } return &JWTMaker{secretKey}, nil } // CreateToken creates a new token for a specific username and duration func (maker *JWTMaker) CreateToken(uuid uuid.UUID, username string, duration time.Duration, tokenType Type) (string, *Payload, error) { payload := NewPayload(uuid, username, duration, tokenType) jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, payload) token, err := jwtToken.SignedString([]byte(maker.secretKey)) return token, payload, err } // VerifyToken checks if the token is valid or not func (maker *JWTMaker) VerifyToken(token string, tokenType Type) (*Payload, error) { keyFunc := func(token *jwt.Token) (interface{}, error) { _, ok := token.Method.(*jwt.SigningMethodHMAC) if !ok { return nil, ErrInvalidToken } return []byte(maker.secretKey), nil } jwtToken, err := jwt.ParseWithClaims(token, &Payload{}, keyFunc) if err != nil { if errors.Is(err, jwt.ErrTokenExpired) { return nil, ErrExpiredToken } return nil, ErrInvalidToken } payload, ok := jwtToken.Claims.(*Payload) if !ok { return nil, ErrInvalidToken } err = payload.Valid(tokenType) if err != nil { return nil, err } return payload, nil }