package utils import ( "errors" "fmt" "time" "github.com/golang-jwt/jwt/v5" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" ) type JWT struct { privateKey []byte publicKey []byte algorithm *jwt.SigningMethodRSA expiresIn time.Duration issuer string audience string } func NewJWT(configuration *models.JWTConfiguration) *JWT { return &JWT{ privateKey: []byte(configuration.PrivateKey), publicKey: []byte(configuration.PublicKey), algorithm: &configuration.Algorithm, expiresIn: configuration.ExpiresIn, issuer: configuration.Issuer, audience: configuration.Audience, } } func (receiver *JWT) Create(id string) (string, error) { privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(receiver.privateKey) if err != nil { return "", fmt.Errorf("failed to parse private key on of : %w", err) } now := time.Now().UTC() claims := jwt.MapClaims{ "id": id, // Our userID "exp": now.Add(receiver.expiresIn).Unix(), // The expiration time after which the token must be disregarded. "aud": receiver.audience, // Audience "iss": receiver.issuer, // Issuer } token, err := jwt.NewWithClaims(receiver.algorithm, claims).SignedString(privateKey) if err != nil { return "", fmt.Errorf("failed to sing on of : %w", err) } return token, nil } func (receiver *JWT) Validate(tokenString string) (string, error) { key, err := jwt.ParseRSAPublicKeyFromPEM(receiver.publicKey) if err != nil { return "", fmt.Errorf("failed to parse rsa public key on of : %w", err) } parseCallback := func(token *jwt.Token) (any, error) { if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { return nil, fmt.Errorf("unexpected signing method: %s", token.Header["alg"]) } return key, nil } token, err := jwt.Parse( tokenString, parseCallback, jwt.WithAudience(receiver.audience), jwt.WithIssuer(receiver.issuer), ) if err != nil { return "", fmt.Errorf("failed to parse jwt token on of : %w", err) } claims, ok := token.Claims.(jwt.MapClaims) if !ok || !token.Valid { return "", errors.New("token is invalid on of ") } data, ok := claims["id"].(string) if !ok { return "", errors.New("data is empty or not a string on of ") } return data, nil }