1. Overview
In this short tutorial, we’re going to take a close look at how to disable logout redirects in Spring Security.
We’ll first start with a brief background on how the logout flow works in Spring Security. Then, we’ll illustrate, through a practical example, how to avoid user redirection after a successful logout.
2. Logout in Spring Security
In short, Spring Security provides out-of-box support for the logout mechanism through the logout() DSL method. Basically, Spring Security triggers log-out when a user hits the default logout URL, which is /logout.
It’s worth mentioning that the default value of the logout URL was /j_spring_security_logout before Spring Security 4.
Spring Security offers the possibility to redirect users to a particular URL after logging out. However, there are some occasions when we want to avoid this behavior.
So, without further ado, let’s see how to implement the logic of disabling logout redirects in Spring Security.
3. Disable Spring Security Logout Redirect
By default, Spring Security redirects users to /login?logout after a successful logout. So, in this section, we’re going to focus on how to prevent user redirection to the login page after logging out.
Note that we can override the default redirect URL with the help of the .logoutSuccessUrl() DSL method.
The main point here is to show how to avoid redirection when the /logout URL is being called from a REST client.
As a matter of fact, the Log**outSuccessHandler interface offers a flexible way to execute custom logic when the logout process is performed successfully.
So here, we’ll use a custom LogoutSuccessHandler to return only a clean 200 status code. That way, it won’t redirect us to any page.
Now, let’s implement the necessary Spring Security configuration required to disable logout redirects:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authz -> authz.requestMatchers("/login")
.permitAll()
.anyRequest()
.authenticated())
.logout(logout -> logout.permitAll()
.logoutSuccessHandler((request, response, authentication) -> {
response.setStatus(HttpServletResponse.SC_OK);
}));
return http.build();
}
}
The important part to note from the above configuration is the logoutSuccessHandler() method. As we can see, we use a lambda expression to define our custom logout success handler.
Bear in mind that we can also create a simple implementation class of the LogoutSuccessHandler interface and use DSL to pass it to the logoutSuccessHandler() method.
4. Testing
Now that we put all the pieces together, let’s test the /logout endpoint to confirm that everything works as expected.
Note that we’ll be using MockMvc to send /logout requests in our test.
First, let’s create a simple test class and inject the MockMvc object in it:
public class LogoutApplicationUnitTest {
@Autowired
private MockMvc mockMvc;
// test case
}
Now, let’s write a method to test our /logout endpoint:
@Test
public void whenLogout_thenDisableRedirect() throws Exception {
this.mockMvc.perform(post("/logout").with(csrf()))
.andExpect(status().isOk())
.andExpect(jsonPath("$").doesNotExist())
.andExpect(unauthenticated())
.andReturn();
}
Lastly, let’s try to break down our test code:
- .perform(post(“/logout”)) invokes the /logout endpoint as a simple POST request
- .with(csrf()) adds the expected _csrf parameter to the query
- .status() returns the status code of the HTTP response
- .jsonPath() allows access to the body of the HTTP response
5. Conclusion
To sum up, we’ve explained and illustrated how to tackle the challenge of disabling logout redirects in Spring Security and Spring Boot.
As usual, the complete source code for this article is available over on GitHub.