Developing a web-application requires a lot of thought. Security and authentication are critical parts; however, in some cases, logging out is being disrespected, underestimated and left to the end.
In this short essay, I will explain Spring's implementation for the logout mechanism, usage of logout when working with oAuth, and maybe most important: cases where logout is not needed.
Spring is very modular and versatile, and almost everything can be replaced or extended. Thus, one can implement his own logout filter and put it in the filter chain. This should be done only if necessary. The best practice is to use the built-in logout implementation Spring provides: the LogoutFilter.
How It Works
First, the filter checks whether logout is required. It does so by the URL – if it ends with the pattern declared in the XML.
Then, Spring fetches the Authentication object from the SecurityContextHolder. This object reflects the Authentication entity for this thread. Using this object, Spring calls all the registered handlers. Usually, this is SecurityContextLogoutHandler, and if “remember me” is involved, another handler is called: PersistentTokenBasedRememberMeServices or TokenBasedRememberMeServices. Both extends AbstractRememberMeServices; the first is relevant when the token was persisted in a DB, the latter is relevant when token is saved in-memory. As mentioned above, Spring enables users to add their own handlers, or to change the current handlers by extending them.
After calling the handlers, there is another call, this time to the “successful handler”: SimpleUrlLogoutSuccessHandler, which actually does nothing but calling its parent, AbstractAuthenticationTargetUrlRequestHandler. This class is relevant for redirecting after the logout.
By default, this handler clears (invalidates) the session. Then, it clears the
Logout and oAuth
All mentioned above is relevant for web-applications. Obviously, oAuth plays in web-applications as well. However, there is no real meaning for logging out from oAuth (maybe this is why the specifications mention nothing about logging out). The reason for this is that the “only” thing oAuth server does is issuing tokens to clients that try to get to a 3rd party protected resource. Once the token is given, the oAuth server technically finished its job (till another token is requested, etc.). Thus, contrary to regular applications, oAuth servers do not keep a context for each client.
The only exception is the “remember me” feature – if this is being used, the oAuth server does keep some knowledge for the client, persisted in a DB or in-memory.
oAuth logout for Non-web Clients
Having said the above, for a non-web client application, things are a bit different.
The “remember me” feature uses the browser’s session, so in a non-web client, the “remember me” will never work. Thus, if the oAuth logout has no “session” to invalidate, and if there is no “remember me” cookie to delete in the oAuth server side, the only thing a non-web client left to do is to delete the token it got from the oAuth server, and that is it.
Logout from oAuth Server - Conclusion
If the client is a regular web application, it should "logout" from the oAuth server, to invalidate the session and delete the "remember me" cookie (if exists). But if the client is a non-web application, there is no need to logout from the oAuth server at all: deleting the token will be enough.
Spring’s Logout and REST
If we write a REST web-application, we will have a problem using the default Spring's logout mechanism. Because Spring redirects the user-agent right after the logout, it returns 302 code - instead of 200. This is not normal return code for REST-clients, which obviously do not care about redirections. In order to solve this little issue, we have to manipulate a bit the logout mechanism.
in the Spring' beans.xml, in the main http section (where we have the login declaration), we should delete the
</logout> statement if it exists. Instead, we will do it manually:
<!-- sec:logout /-->
<sec:custom-filter position="LOGOUT_FILTER" ref="restLogoutFilter" />
<bean id="restLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<bean class="com.ohadr.cbenchmarkr.core.NoRedirectLogoutSuccessHandler" />
and we will replace the default success-handler (see above) with a one that does not redirect:
public class NoRedirectLogoutSuccessHandler implements LogoutSuccessHandler
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException