diff --git a/backend/internal/http/handler/dto.go b/backend/internal/http/handler/dto.go index 8f375e3..bf513ed 100644 --- a/backend/internal/http/handler/dto.go +++ b/backend/internal/http/handler/dto.go @@ -47,7 +47,8 @@ type registerCompanyTarget struct { } type loginRequest struct { - Username string `json:"username"` + Username string `json:"username,omitempty"` + Email string `json:"email,omitempty"` Password string `json:"password"` } diff --git a/backend/internal/http/handler/handler.go b/backend/internal/http/handler/handler.go index da1d976..0152ec6 100644 --- a/backend/internal/http/handler/handler.go +++ b/backend/internal/http/handler/handler.go @@ -106,7 +106,12 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) { return } - token, exp, err := h.svc.Authenticate(r.Context(), req.Username, req.Password) + identifier := req.Email + if identifier == "" { + identifier = req.Username + } + + token, exp, err := h.svc.Authenticate(r.Context(), identifier, req.Password) if err != nil { writeError(w, http.StatusUnauthorized, err) return diff --git a/backend/internal/usecase/usecase.go b/backend/internal/usecase/usecase.go index 655e231..46bff83 100644 --- a/backend/internal/usecase/usecase.go +++ b/backend/internal/usecase/usecase.go @@ -604,11 +604,16 @@ func (s *Service) RegisterAccount(ctx context.Context, company *domain.Company, } // Authenticate validates credentials and emits a signed JWT. -func (s *Service) Authenticate(ctx context.Context, username, password string) (string, time.Time, error) { - user, err := s.repo.GetUserByUsername(ctx, username) +func (s *Service) Authenticate(ctx context.Context, identifier, password string) (string, time.Time, error) { + // Try fetching by username first + user, err := s.repo.GetUserByUsername(ctx, identifier) if err != nil { - // Return generic error to avoid leaking DB details or user existence - return "", time.Time{}, errors.New("invalid credentials") + // Try fetching by email + user, err = s.repo.GetUserByEmail(ctx, identifier) + if err != nil { + // Return generic error to avoid leaking DB details or user existence + return "", time.Time{}, errors.New("invalid credentials") + } } if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(s.pepperPassword(password))); err != nil {