package utils import ( "os" "time" "github.com/golang-jwt/jwt/v5" ) type SubscriberTokenClaims struct { Email string `json:"email"` jwt.RegisteredClaims } // GenerateSubscriberToken creates a signed token for a subscriber email, expires in `ttl` minutes func GenerateSubscriberToken(email string, ttlMinutes int) (string, error) { if ttlMinutes <= 0 { ttlMinutes = 60 } now := time.Now() claims := &SubscriberTokenClaims{ Email: email, RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(time.Duration(ttlMinutes) * time.Minute)), Issuer: "fotbal-club", }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(getJWTSecret())) } // ParseSubscriberToken validates and returns the email embedded in the token func ParseSubscriberToken(tokenString string) (string, error) { token, err := jwt.ParseWithClaims(tokenString, &SubscriberTokenClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(getJWTSecret()), nil }) if err != nil { return "", err } if claims, ok := token.Claims.(*SubscriberTokenClaims); ok && token.Valid { return claims.Email, nil } return "", jwt.ErrTokenMalformed } func getJWTSecret() string { s := os.Getenv("JWT_SECRET") if s == "" { return "default-secret-key-change-in-production" } return s }