package auth import ( "fmt" "time" "github.com/golang-jwt/jwt/v5" ) type Claims struct { UserID int `json:"user_id"` Username string `json:"username"` Email string `json:"email,omitempty"` jwt.RegisteredClaims } func GenerateJWT(userID int, username, email string, cfg *Config) (string, int64, error) { expiresAt := time.Now().Add(time.Duration(cfg.JWTExpiry) * time.Second) claims := &Claims{ UserID: userID, Username: username, Email: email, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(expiresAt), IssuedAt: jwt.NewNumericDate(time.Now()), Issuer: "opal-task", }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) signedToken, err := token.SignedString(cfg.JWTSecret) if err != nil { return "", 0, err } return signedToken, expiresAt.Unix(), nil } func ValidateJWT(tokenString string, cfg *Config) (*Claims, error) { token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return cfg.JWTSecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*Claims); ok && token.Valid { return claims, nil } return nil, fmt.Errorf("invalid token") }