diff --git a/backend-old/internal/http/handler/handler.go b/backend-old/internal/http/handler/handler.go index 5fc15d1..63439c3 100644 --- a/backend-old/internal/http/handler/handler.go +++ b/backend-old/internal/http/handler/handler.go @@ -123,12 +123,12 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) { return } - identifier := req.Email - if identifier == "" { - identifier = req.Username + if req.Username == "" { + writeError(w, http.StatusBadRequest, errors.New("username is required")) + return } - token, exp, err := h.svc.Authenticate(r.Context(), identifier, req.Password) + token, exp, err := h.svc.Login(r.Context(), req.Username, req.Password) if err != nil { writeError(w, http.StatusUnauthorized, err) return diff --git a/backend-old/internal/usecase/auth_usecase.go b/backend-old/internal/usecase/auth_usecase.go new file mode 100644 index 0000000..460f386 --- /dev/null +++ b/backend-old/internal/usecase/auth_usecase.go @@ -0,0 +1,41 @@ +package usecase + +import ( + "context" + "errors" + "strings" + "time" + + "github.com/golang-jwt/jwt/v5" + "golang.org/x/crypto/bcrypt" +) + +// Login validates credentials using username and returns a signed JWT. +func (s *Service) Login(ctx context.Context, username, password string) (string, time.Time, error) { + if strings.TrimSpace(username) == "" { + return "", time.Time{}, errors.New("username is required") + } + + user, err := s.repo.GetUserByUsername(ctx, username) + if err != nil { + return "", time.Time{}, errors.New("invalid credentials") + } + + if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(s.pepperPassword(password))); err != nil { + return "", time.Time{}, errors.New("invalid credentials") + } + + expiresAt := time.Now().Add(s.tokenTTL) + claims := jwt.MapClaims{ + "user_id": user.ID.String(), + "company_id": user.CompanyID.String(), + "role": user.Role, + } + + signed, err := s.signToken(claims, expiresAt) + if err != nil { + return "", time.Time{}, err + } + + return signed, expiresAt, nil +}