package auth import ( "errors" "time" "github.com/golang-jwt/jwt/v5" "golang.org/x/crypto/bcrypt" ) type JWTService struct { secretKey []byte issuer string } func NewJWTService(secret string, issuer string) *JWTService { return &JWTService{ secretKey: []byte(secret), issuer: issuer, } } func (s *JWTService) HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) return string(bytes), err } func (s *JWTService) VerifyPassword(hash, password string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } func (s *JWTService) GenerateToken(userID, tenantID string, roles []string) (string, error) { claims := jwt.MapClaims{ "sub": userID, "tenant": tenantID, "roles": roles, "iss": s.issuer, "exp": time.Now().Add(time.Hour * 24).Unix(), // 24 hours "iat": time.Now().Unix(), } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(s.secretKey) } func (s *JWTService) ValidateToken(tokenString string) (map[string]interface{}, error) { token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, errors.New("unexpected signing method") } return s.secretKey, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") }