Spring Single Page Application: CSRF token changes silently after login, logout, etc.
As I know, in a Spring + JavaScript single page application, we need to send a CSRF token to the client somehow.
The recommended way would be to have CsrfHeaderFilter
, as described in this Spring guide . Following this approach, when the application starts, it will send a GET request to the server and retrieve the token.
But I see that on certain events like login or logout, Spring Security changes the token. CsrfHeaderFilter
comes in early and therefore cannot detect the change. Hence, I need to send another GET request after such events.
I tried to peek at the Spring security code to see if there would be a way to send the modified token along with these login or logout requests, so that another GET request would be saved. But couldn't find a way.
Liked to find out if a bogus GET request is sending after login, logout, etc., as I am currently doing, looks like a good solution. Or maybe there is a better way?
If there is currently no way to avoid this redundant GET request, I was wondering if this would be the ticket for Spring Security to come up with something after which it would be possible.
source to share
A similar situation happened with CookieCsrfTokenRepository.
The application I was working in has a custom implementation of a login using a REST service. The service has a call to httpServletRequest.logout () internally, which (as I found out) resulted in the XSRF-TOKEN cookies being cleared in response:
Set-Cookie:XSRF-TOKEN=; Max-Age=0; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ibdrs; Secure
Without the new XSRF-TOKEN value in the answer, I had two options:
-
Make a dummy request for a new XSRF-TOKEN right after login (as OP suggested)
-
Update XSRF-TOKEN in the same login answer as for clearing the cookie.
It turned out that the second option can be achieved:
-
Created my own CustomCookieCsrfTokenRepository as a copy of CookieCsrfTokenRepository (source code here ). If it weren't definitive, it would be sufficient to expand it instead of copying it.
-
Changed all occurrences of CookieCsrfTokenRepository to CustomCookieCsrfTokenRepository inside copy
-
Replaced the saveToken method with a newer version that never clears the cookie:
@Override public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) { if (token == null) { token = generateToken(request); } String tokenValue = token.getToken(); Cookie cookie = new Cookie(this.cookieName, tokenValue); cookie.setSecure(request.isSecure()); if (this.cookiePath != null && !this.cookiePath.isEmpty()) { cookie.setPath(this.cookiePath); } else { cookie.setPath(this.getRequestContext(request)); } cookie.setMaxAge(-1); if (cookieHttpOnly && setHttpOnlyMethod != null) { ReflectionUtils.invokeMethod(setHttpOnlyMethod, cookie, Boolean.TRUE); } response.addCookie(cookie); }
-
Configure HttpSecurity to use the new class:
.csrf() .csrfTokenRepository(CustomCookieCsrfTokenRepository.withHttpOnlyFalse()) .and()
source to share