diff --git a/spring-security-modules/spring-security-web-login-2/README.md b/spring-security-modules/spring-security-web-login-2/README.md
new file mode 100644
index 0000000000..826301c0fe
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/README.md
@@ -0,0 +1,9 @@
+## Spring Security Login - 2
+
+This module contains articles about login/logout mechanisms with Spring Security.
+
+## Relevant articles:
+
+- [Manual Logout With Spring Security](https://www.baeldung.com/spring-security-manual-logout)
+- [How to Disable Spring Security Logout Redirects](https://www.baeldung.com/spring-security-disable-logout-redirects)
+- More articles: [[<-- prev]](/spring-security-modules/spring-security-web-login)
diff --git a/spring-security-modules/spring-security-web-login-2/pom.xml b/spring-security-modules/spring-security-web-login-2/pom.xml
new file mode 100644
index 0000000000..d5e5a4426e
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/pom.xml
@@ -0,0 +1,60 @@
+
+
+ 4.0.0
+ spring-security-web-login-2
+ 0.0.1-SNAPSHOT
+ spring-security-web-login-2
+ jar
+
+
+ com.baeldung
+ parent-boot-2
+ 0.0.1-SNAPSHOT
+ ../../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+ org.thymeleaf.extras
+ thymeleaf-extras-springsecurity5
+
+
+ org.springframework
+ spring-test
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/logoutredirects/LogoutApplication.java b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/logoutredirects/LogoutApplication.java
new file mode 100644
index 0000000000..ef8175ffb2
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/logoutredirects/LogoutApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.logoutredirects;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class LogoutApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(LogoutApplication.class, args);
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/logoutredirects/securityconfig/SpringSecurityConfig.java b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/logoutredirects/securityconfig/SpringSecurityConfig.java
new file mode 100644
index 0000000000..64141f63d8
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/logoutredirects/securityconfig/SpringSecurityConfig.java
@@ -0,0 +1,27 @@
+package com.baeldung.logoutredirects.securityconfig;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+@EnableWebSecurity
+public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests(authz -> authz.mvcMatchers("/login")
+ .permitAll()
+ .anyRequest()
+ .authenticated())
+ .logout(logout -> logout.permitAll()
+ .logoutSuccessHandler((request, response, authentication) -> {
+ response.setStatus(HttpServletResponse.SC_OK);
+ }));
+
+ }
+
+}
diff --git a/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/manuallogout/ManualLogoutApplication.java b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/manuallogout/ManualLogoutApplication.java
new file mode 100644
index 0000000000..50ea356f03
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/manuallogout/ManualLogoutApplication.java
@@ -0,0 +1,11 @@
+package com.baeldung.manuallogout;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ManualLogoutApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(ManualLogoutApplication.class, args);
+ }
+}
diff --git a/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/manuallogout/SimpleSecurityConfiguration.java b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/manuallogout/SimpleSecurityConfiguration.java
new file mode 100644
index 0000000000..303a139215
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/main/java/com/baeldung/manuallogout/SimpleSecurityConfiguration.java
@@ -0,0 +1,95 @@
+package com.baeldung.manuallogout;
+
+import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.CACHE;
+import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES;
+import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.EXECUTION_CONTEXTS;
+import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.STORAGE;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
+import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
+import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
+
+@Configuration
+@EnableWebSecurity
+public class SimpleSecurityConfiguration {
+
+ private static Logger logger = LoggerFactory.getLogger(SimpleSecurityConfiguration.class);
+
+ @Order(4)
+ @Configuration
+ public static class LogoutOnRequestConfiguration extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.antMatcher("/request/**")
+ .authorizeRequests(authz -> authz.anyRequest()
+ .permitAll())
+ .logout(logout -> logout.logoutUrl("/request/logout")
+ .addLogoutHandler((request, response, auth) -> {
+ try {
+ request.logout();
+ } catch (ServletException e) {
+ logger.error(e.getMessage());
+ }
+ }));
+ }
+ }
+
+ @Order(3)
+ @Configuration
+ public static class DefaultLogoutConfiguration extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.antMatcher("/basic/**")
+ .authorizeRequests(authz -> authz.anyRequest()
+ .permitAll())
+ .logout(logout -> logout.logoutUrl("/basic/basiclogout"));
+ }
+ }
+
+ @Order(2)
+ @Configuration
+ public static class AllCookieClearingLogoutConfiguration extends WebSecurityConfigurerAdapter {
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.antMatcher("/cookies/**")
+ .authorizeRequests(authz -> authz.anyRequest()
+ .permitAll())
+ .logout(logout -> logout.logoutUrl("/cookies/cookielogout")
+ .addLogoutHandler(new SecurityContextLogoutHandler())
+ .addLogoutHandler((request, response, auth) -> {
+ for (Cookie cookie : request.getCookies()) {
+ String cookieName = cookie.getName();
+ Cookie cookieToDelete = new Cookie(cookieName, null);
+ cookieToDelete.setMaxAge(0);
+ response.addCookie(cookieToDelete);
+ }
+ }));
+ }
+ }
+
+ @Order(1)
+ @Configuration
+ public static class ClearSiteDataHeaderLogoutConfiguration extends WebSecurityConfigurerAdapter {
+
+ private static final ClearSiteDataHeaderWriter.Directive[] SOURCE = { CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS };
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.antMatcher("/csd/**")
+ .authorizeRequests(authz -> authz.anyRequest()
+ .permitAll())
+ .logout(logout -> logout.logoutUrl("/csd/csdlogout")
+ .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE))));
+ }
+ }
+}
diff --git a/spring-security-modules/spring-security-web-login-2/src/main/resources/application.properties b/spring-security-modules/spring-security-web-login-2/src/main/resources/application.properties
new file mode 100644
index 0000000000..7fc55efed9
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/main/resources/application.properties
@@ -0,0 +1,5 @@
+server.port=8081
+
+logging.level.root=INFO
+
+logging.level.org.springframework.security=DEBUG
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login-2/src/main/resources/logback.xml b/spring-security-modules/spring-security-web-login-2/src/main/resources/logback.xml
new file mode 100644
index 0000000000..7d900d8ea8
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login-2/src/test/java/com/baeldung/logoutredirects/LogoutApplicationUnitTest.java b/spring-security-modules/spring-security-web-login-2/src/test/java/com/baeldung/logoutredirects/LogoutApplicationUnitTest.java
new file mode 100644
index 0000000000..519a6bdc99
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/test/java/com/baeldung/logoutredirects/LogoutApplicationUnitTest.java
@@ -0,0 +1,34 @@
+package com.baeldung.logoutredirects;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+@RunWith(SpringRunner.class)
+@WebMvcTest()
+public class LogoutApplicationUnitTest {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @WithMockUser(value = "spring")
+ @Test
+ public void whenLogout_thenDisableRedirect() throws Exception {
+
+ this.mockMvc.perform(post("/logout").with(csrf()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$").doesNotExist())
+ .andExpect(unauthenticated())
+ .andReturn();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login-2/src/test/java/com/baeldung/manuallogout/ManualLogoutIntegrationTest.java b/spring-security-modules/spring-security-web-login-2/src/test/java/com/baeldung/manuallogout/ManualLogoutIntegrationTest.java
new file mode 100644
index 0000000000..06dc01e116
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/test/java/com/baeldung/manuallogout/ManualLogoutIntegrationTest.java
@@ -0,0 +1,96 @@
+package com.baeldung.manuallogout;
+
+import static org.junit.Assert.assertNull;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpSession;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpSession;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+
+@RunWith(SpringRunner.class)
+@WebMvcTest()
+public class ManualLogoutIntegrationTest {
+
+ private static final String CLEAR_SITE_DATA_HEADER = "Clear-Site-Data";
+ public static final int EXPIRY = 60 * 10;
+ public static final String COOKIE_NAME = "customerName";
+ public static final String COOKIE_VALUE = "myName";
+ public static final String ATTRIBUTE_NAME = "att";
+ public static final String ATTRIBUTE_VALUE = "attvalue";
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @WithMockUser(value = "spring")
+ @Test
+ public void givenLoggedUserWhenUserLogoutThenSessionClearedAndNecessaryCookieCleared() throws Exception {
+
+ this.mockMvc.perform(post("/basic/basiclogout").secure(true)
+ .with(csrf()))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(unauthenticated())
+ .andReturn();
+ }
+
+ @WithMockUser(value = "spring")
+ @Test
+ public void givenLoggedUserWhenUserLogoutThenSessionClearedAndAllCookiesCleared() throws Exception {
+
+ MockHttpSession session = new MockHttpSession();
+ session.setAttribute(ATTRIBUTE_NAME, ATTRIBUTE_VALUE);
+
+ Cookie randomCookie = new Cookie(COOKIE_NAME, COOKIE_VALUE);
+ randomCookie.setMaxAge(EXPIRY); // 10 minutes
+
+ MockHttpServletRequest requestStateAfterLogout = this.mockMvc.perform(post("/cookies/cookielogout").secure(true)
+ .with(csrf())
+ .session(session)
+ .cookie(randomCookie))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(unauthenticated())
+ .andExpect(cookie().maxAge(COOKIE_NAME, 0))
+ .andReturn()
+ .getRequest();
+
+ HttpSession sessionStateAfterLogout = requestStateAfterLogout.getSession();
+ assertNull(sessionStateAfterLogout.getAttribute(ATTRIBUTE_NAME));
+ }
+
+ @WithMockUser(value = "spring")
+ @Test
+ public void givenLoggedUserWhenUserLogoutThenClearDataSiteHeaderPresent() throws Exception {
+
+ this.mockMvc.perform(post("/csd/csdlogout").secure(true)
+ .with(csrf()))
+ .andDo(print())
+ .andExpect(status().is3xxRedirection())
+ .andExpect(header().exists(CLEAR_SITE_DATA_HEADER))
+ .andReturn();
+ }
+
+ @WithMockUser(value = "spring")
+ @Test
+ public void givenLoggedUserWhenUserLogoutOnRequestThenSessionCleared() throws Exception {
+
+ this.mockMvc.perform(post("/request/logout").secure(true)
+ .with(csrf()))
+ .andExpect(status().is3xxRedirection())
+ .andExpect(unauthenticated())
+ .andReturn();
+ }
+}
\ No newline at end of file
diff --git a/spring-security-modules/spring-security-web-login-2/src/test/resources/logback-test.xml b/spring-security-modules/spring-security-web-login-2/src/test/resources/logback-test.xml
new file mode 100644
index 0000000000..8d4771e308
--- /dev/null
+++ b/spring-security-modules/spring-security-web-login-2/src/test/resources/logback-test.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n
+
+
+
+
+
+
+
\ No newline at end of file