package auth import ( "encoding/json" "log/slog" "net/http" "github.com/food-ai/backend/internal/middleware" ) const maxRequestBodySize = 1 << 20 // 1 MB type Handler struct { service *Service } func NewHandler(service *Service) *Handler { return &Handler{service: service} } type loginRequest struct { FirebaseToken string `json:"firebase_token"` } type refreshRequest struct { RefreshToken string `json:"refresh_token"` } func (h *Handler) Login(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestBodySize) var req loginRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorJSON(w, http.StatusBadRequest, "invalid request body") return } if req.FirebaseToken == "" { writeErrorJSON(w, http.StatusBadRequest, "firebase_token is required") return } resp, err := h.service.Login(r.Context(), req.FirebaseToken) if err != nil { writeErrorJSON(w, http.StatusUnauthorized, "authentication failed") return } writeJSON(w, http.StatusOK, resp) } func (h *Handler) Refresh(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRequestBodySize) var req refreshRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeErrorJSON(w, http.StatusBadRequest, "invalid request body") return } if req.RefreshToken == "" { writeErrorJSON(w, http.StatusBadRequest, "refresh_token is required") return } resp, err := h.service.Refresh(r.Context(), req.RefreshToken) if err != nil { writeErrorJSON(w, http.StatusUnauthorized, "invalid refresh token") return } writeJSON(w, http.StatusOK, resp) } func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) { userID := middleware.UserIDFromCtx(r.Context()) if userID == "" { writeErrorJSON(w, http.StatusUnauthorized, "unauthorized") return } if err := h.service.Logout(r.Context(), userID); err != nil { writeErrorJSON(w, http.StatusInternalServerError, "logout failed") return } writeJSON(w, http.StatusOK, map[string]string{"status": "ok"}) } type errorResponse struct { Error string `json:"error"` } func writeErrorJSON(w http.ResponseWriter, status int, msg string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(errorResponse{Error: msg}); err != nil { slog.Error("failed to write error response", "err", err) } } func writeJSON(w http.ResponseWriter, status int, v interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) if err := json.NewEncoder(w).Encode(v); err != nil { slog.Error("failed to write JSON response", "err", err) } }