When developing secure web applications with Spring Security, one of the most frustrating issues developers encounter is the following error:
Exceeded maxRedirects. Probably stuck in a redirect loop
This error typically indicates that the application is continuously redirecting a request between two or more URLs, eventually exceeding the maximum number of allowed redirects. In most cases, the root cause is an incorrect Spring Security configuration, improperly secured endpoints, or authentication logic that redirects users back to protected resources.
This guide explains the common causes of redirect loops in Spring Security and demonstrates how to diagnose and resolve them.
Understanding Redirect Loops
A redirect loop occurs when:
- A user requests a protected page.
- Spring Security redirects the user to a login page.
- The login page itself requires authentication.
- Spring Security redirects again to the login page.
- The cycle repeats indefinitely.
Example flow:
/test/2
↓
/login
↓
/login
↓
/login
↓
Exceeded maxRedirects
Common Cause #1: Login Page Is Protected
One of the most frequent mistakes is securing the login page itself.
Incorrect Configuration
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
);
return http.build();
}
In this configuration:
/loginrequires authentication.- Spring Security redirects unauthenticated users to
/login. /loginitself requires authentication.- Infinite redirect loop occurs.
Correct Configuration
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
);
return http.build();
}
Now anyone can access the login page.
Common Cause #2: Public Endpoints Not Properly Whitelisted
Suppose the requirement is:
/test/1→ Public/test/2→ Authenticated
Correct Security Configuration
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/test/1").permitAll()
.requestMatchers("/test/2").authenticated()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
If /test/1 is accidentally omitted from permitAll(), requests may be redirected unexpectedly.
Common Cause #3: Incorrect Success or Failure URLs
Authentication success and failure handlers can create loops.
Problematic Example
.formLogin(form -> form
.defaultSuccessUrl("/login")
)
After successful login:
/login
↓
authenticate
↓
/login
↓
authenticate
↓
loop
Correct Example
.formLogin(form -> form
.defaultSuccessUrl("/dashboard", true)
)
Common Cause #4: Reverse Proxy Configuration
Applications behind:
- Nginx
- Apache
- Load Balancers
- Kubernetes Ingress
may encounter redirect loops due to HTTP/HTTPS mismatches.
Example
Browser:
https://example.com
Proxy forwards:
http://localhost:8080
Spring thinks the request is HTTP and redirects:
https://example.com/login
The proxy forwards again, creating a loop.
Solution
Enable forwarded headers:
server.forward-headers-strategy=framework
Or:
@Bean
ForwardedHeaderFilter forwardedHeaderFilter() {
return new ForwardedHeaderFilter();
}
Common Cause #5: Session Problems
If the session cannot be created or maintained:
- User logs in successfully.
- Session cookie is lost.
- Next request appears unauthenticated.
- User is redirected to login again.
Potential causes include:
- Invalid cookie settings
- Domain mismatch
- Secure cookie issues
- Browser blocking cookies
Check browser developer tools:
Application → Cookies
Verify that:
- Session cookie exists
- Cookie domain is correct
- Cookie path is correct
Common Cause #6: Custom Security Filters
Custom filters may accidentally trigger redirects.
Example:
if(authentication == null) {
response.sendRedirect("/login");
}
If the filter executes on /login itself:
/login
↓
custom filter
↓
/login
↓
custom filter
↓
loop
Always exclude authentication pages from custom redirect logic.
Example:
if(request.getRequestURI().equals("/login")) {
filterChain.doFilter(request, response);
return;
}
How to Diagnose Redirect Loops
Enable Spring Security Debug Logging
logging.level.org.springframework.security=DEBUG
Or:
@EnableWebSecurity(debug = true)
This produces detailed logs showing:
Securing GET /test/2
Redirecting to /login
Securing GET /login
Redirecting to /login
The repeated pattern quickly reveals the source of the loop.
Test with cURL
Inspect redirect behavior directly:
curl -I http://localhost:8080/test/2
Follow redirects:
curl -L http://localhost:8080/test/2
Or show each redirect step:
curl -v http://localhost:8080/test/2
Look for repeated Location headers.
Complete Example
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/test/1").permitAll()
.requestMatchers("/login").permitAll()
.requestMatchers("/test/2").authenticated()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults());
return http.build();
}
}
Behavior:
| Endpoint | Authentication Required |
|---|---|
/test/1 | No |
/login | No |
/test/2 | Yes |
| Other endpoints | Yes |
Best Practices
- Always whitelist login and logout endpoints.
- Explicitly define public resources.
- Verify success and failure redirect URLs.
- Enable Spring Security debug logging during troubleshooting.
- Validate session cookie behavior.
- Carefully review custom filters and interceptors.
- Verify proxy and HTTPS forwarding configuration.
Conclusion
The “Exceeded maxRedirects. Probably stuck in a redirect loop” error is usually caused by a misconfiguration in Spring Security, authentication flows, session handling, or reverse proxy setups. By carefully reviewing endpoint permissions, login page accessibility, redirect targets, and session behavior, developers can quickly identify and eliminate redirect loops.
A well-structured Spring Security configuration should clearly separate public and protected endpoints, ensure login pages remain accessible, and avoid circular redirect paths that trap users in endless authentication cycles.


