feat(router): add smart 401 error handler for HTML vs API requests
- Add strings import for Accept header parsing - Add wantsHTML() helper function to detect HTML vs API requests - Checks Accept header for text/html - Checks HX-Request header for HTMX requests - Checks X-Requested-With for AJAX (should return JSON) - Defaults to JSON for API routes - Update JWT middleware ErrorHandler to: - Redirect HTML requests to /login?session=expired - Return JSON error for API requests with session_expired message - Enables browser navigation to redirect gracefully while API calls return proper error responses This fixes the issue where protected routes returned JSON 401 for browser navigation instead of redirecting to login.
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"bookhoard/internal/sync"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
@@ -85,11 +86,44 @@ func createJWTMiddleware(cfg *Config) echo.MiddlewareFunc {
|
||||
})
|
||||
},
|
||||
ErrorHandler: func(c echo.Context, err error) error {
|
||||
return c.JSON(http.StatusUnauthorized, map[string]string{"error": err.Error()})
|
||||
// Check if this is a page request (browser navigation)
|
||||
if wantsHTML(c.Request().Header) {
|
||||
// Page request → Redirect to login with message
|
||||
loginURL := "/login?session=expired"
|
||||
return c.Redirect(http.StatusFound, loginURL)
|
||||
}
|
||||
|
||||
// API request → Return JSON error
|
||||
return c.JSON(http.StatusUnauthorized, map[string]string{
|
||||
"error": "session_expired",
|
||||
"message": "Your session has expired. Please log in again.",
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// wantsHTML determines if the request expects HTML response
|
||||
func wantsHTML(header http.Header) bool {
|
||||
// Check Accept header
|
||||
accept := header.Get("Accept")
|
||||
if accept != "" && (accept == "text/html" || strings.Contains(accept, "text/html")) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check HTMX request
|
||||
if header.Get("HX-Request") == "true" {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check for AJAX requests (should get JSON)
|
||||
if header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Default to JSON for API routes
|
||||
return false
|
||||
}
|
||||
|
||||
// RegisterRoutes registers all application routes
|
||||
func RegisterRoutes(cfg *Config) *handlers.Handler {
|
||||
e := cfg.Echo
|
||||
|
||||
Reference in New Issue
Block a user