-
Notifications
You must be signed in to change notification settings - Fork 43
Description
Problem
When an HTMX-powered page has polling or dynamic fragment requests, and the user's session expires, Spring Security's default LoginUrlAuthenticationEntryPoint sends a 302 redirect to the login page. HTMX transparently follows the redirect and swaps the full login page HTML into each target element, resulting in multiple broken login forms rendered inside card containers.
This is a common issue for any Spring Boot + Thymeleaf + HTMX application using the DS Spring User Framework.
Screenshot Context
In MagicMenu's admin dashboard (the first project to hit this), each HTMX-polled metric card renders a full login page when the session expires — Google button, email/password form, register link — all crammed into card-width containers.
Proposed Solution
1. Create HtmxAwareAuthenticationEntryPoint
A new AuthenticationEntryPoint implementation that wraps LoginUrlAuthenticationEntryPoint:
- HTMX requests (
HX-Request: trueheader) → Return 401 with JSON body:{"error": "authentication_required", "message": "Session expired. Please log in.", "loginUrl": "/user/login"} - Browser requests → Delegate to
LoginUrlAuthenticationEntryPoint(current 302 redirect behavior)
~40 lines. Location: com.digitalsanctuary.spring.user.security.HtmxAwareAuthenticationEntryPoint
2. Wire into WebSecurityConfig.securityFilterChain()
Currently, exceptionHandling() is only configured when OAuth2 is enabled. Change to always configure it:
- For standard form login: use
HtmxAwareAuthenticationEntryPointwrappingLoginUrlAuthenticationEntryPoint - For OAuth2: continue using
CustomOAuth2AuthenticationEntryPoint(or wrap it with HTMX awareness too)
3. Allow consumer override via @ConditionalOnMissingBean
Follow the existing RegistrationGuard pattern — if a consuming application provides its own AuthenticationEntryPoint bean, use it instead of the default HtmxAwareAuthenticationEntryPoint.
Backward Compatibility
100% backward-compatible:
- Browser requests get the same 302 redirect they always did
- Only HTMX requests (which were broken before) get the new 401 behavior
- Consumers can override with their own entry point bean if needed
Acceptance Criteria
-
HtmxAwareAuthenticationEntryPointcreated and unit tested -
WebSecurityConfigalways configuresexceptionHandling()with the HTMX-aware entry point - Consumer override works via
@ConditionalOnMissingBean - Existing form login, OAuth2, MFA, and WebAuthn flows unaffected
- Documentation updated
References
- Discovered via MagicMenu issue MM-213 (admin dashboard shows login page in each HTMX card when session expires)
- HTMX request detection pattern: check for
HX-Request: trueheader - Existing HTMX detection in MagicMenu's
TermsAcceptanceInterceptorvalidates this approach