In the last article, we learned how to create login using spring security. In this article, we will learn how to perform spring security logout. Spring security provides a build in capabilities to handle most of the complex tasks during the logout.
Spring Security Logout
Logout id an integral part of any secure application. Logout ensure that all sensitive information is removed or invalidated once customer performs the logout. Spring security store authentication information in the session. Spring security automatically handles the following tasks for the application.
- Invalidating the HTTP Session.
- Cleaning up any RememberMe authentication configuration.
- Clearing the SecurityContextHolder.
- Redirect user to the configured page.
In this post, we will inspect the logout functionality using spring security and spring boot along with the extension points.
1. Application Setup
Let’s start by creating a sample application. You can also download the complete application from our GitHub repository. If needed, you can use IDE or Spring initializr to create the application. We are adding the following dependencies for our application by utilizing Spring boot auto configuration feature.
- Spring security auto configuration.
- Spring web starter.
- Thymeleaf.
This is how the pom.xml look like:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.javadevjoural</groupId>
<artifactId>spring-security-logout</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Spring Security Logout</name>
<description>Spring Security Logout</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. Logout Configuration
Since Spring security will handle most of the heavy lifting during the logout process, we only need to configure few details our custom security configuration class extending the WebSecurityConfigurerAdapter. Here is the basic configuration to enable the logout feature:
protected void configure(HttpSecurity http) throws Exception {
http
.logout(logout -> logout
);
}
There are few things which we should keep in mind when enabling the logout feature:
- On successful logout, customer by default redirected to the
/login?logout
. Spring security provides flexibility to change the URL. - If CSRF protection is active (default), Spring security expects the logout request must of
POST
type, we can use theGET
logout request by disabling the CSRF protection.
Here is the complete reference in case you need more control on the logout process:
protected void configure(HttpSecurity http) throws Exception {
http
.logout(logout -> logout
.logoutUrl("/my/logout")
.logoutSuccessUrl("/home")
.logoutSuccessHandler(logoutSuccessHandler)
.invalidateHttpSession(true)
.addLogoutHandler(logoutHandler)
.deleteCookies(cookieNamesToClear)
)
}
logoutSuccessURL
– help to redirect the user to a landing page post logout, the default The default is/login?logout
(In our case, we are redirecting to the home page).logoutSuccessHandler
– Handler, which triggers once the logout is complete. We can use this to handle redirection or forwarding to the destination.Keep in mind that thelogoutSuccessUrl()
will be ignored if we configure thelogoutSuccessHandler
.invalidateHttpSession
– Controls if HTTP session should be invalided. The default value is true.deleteCookies
– Delete any secure cookies (in case we are setting during the login.)
To customize logout functionality, you can add <a href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/authentication/logout/LogoutHandler.html" target="_blank" rel="noopener noreferrer">LogoutHandler</a>
and/or <a title="LogoutSuccessHandler" href="https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/authentication/logout/LogoutSuccessHandler.html" target="_blank" rel="noopener noreferrer">LogoutSuccessHandler</a>
implementations.
3. Spring Security Logout UI
We need to give the option to the customer to click on the logout link. Spring security provides following 2 options:
- Perform the POST logout (this is default and recommended.)
- Perform the GET logout by disabling CSRF feature.
We are using the Thymeleaf as the templating engine, please change the code as per your UI.
<div sec:authorize="isAuthenticated()">
<a href="javascript: document.logoutForm.submit()" class="dropdown-toggle">Sign out</a>
<form name="logoutForm" th:action="@{/logout}" method="post" th:hidden="true">
<input hidden type="submit" value="Sign Out" />
</form>
</div>
We are doing a POST logout request. Also remember following:
- Your request for action should be /logout. This is the logout handler from Spring security.
We are using sec:authorize="isAuthenticated()
To ensure that logout link is only visible to the logged in user. If you are using Thymeleaf, you need to add additional dependency in your pom.xml
to enable suppport for Spring Security Dialect using the Thymeleaf – Spring Security integration modules.
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
3.1. Logout Using GET
If you can’t perform a POST request and like to fall back to GET logout request, you need the following changes in your application.
- Disable CSRF.
- Conver POST request to GET on UI.
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
...
}
UI changes
<div sec:authorize="isAuthenticated()">
<a th:href="@{/logout}">Logout</a>
</div>
4. Testing Logout
Our configuration and changes are complete, start the application, once application is up and running do a login.
Logged In Screen:
If we check the cookies, we will see the following cookies:
JSESSIONID
.- Custom Cookie (Stored during login process)
When we perform the logout, Spring Security will invalidate the session and delete any additional cookie (if we configure it in the logout configuration). To check this, perfrom the following additional steps
- Note down the JSESSIONID id after the login.
- Do a logout and check the JSESSIONID again, both ID will be different.
Here is the screen after logout:
dummyCookie
is no longer available post logout since we told Spring security to delete it on successful logout.
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.logout(logout->logout
.deleteCookies("dummyCookie")
);
}
Summary
In this post, we looked at the Spring security logout feature. Spring security provides build in support for the logout with a small configuration and code changes. At the same time it’s flexible enough to allow you to customize the logout behaviour for your application. In Summary:
- How to perfrom the logout in Spring application.
- What are the configuration required to enable logout feature?
- How to customize the logout behaviout by injecting your own logout success handlers.
This post is part of our Spring security course and the code base is available on the GitHub