Reputation: 72
As shown below, the document says that you can make a logout post request with the csrf token. If I got it right.... https://docs.spring.io/spring-security/reference/servlet/authentication/logout.html
Aside from providing a valuable double-checking mechanism for the user, it also provides a simple way to provide the needed CSRF token to POST /logout.
But 403 errors occur when CSRF is enabled and logout request. And I was able to fix the error by specifying csrf().ignoreAntMatchers({logout url})
.
As forementioned, the document said to provide csrf tokens, but why does it work without errors when I used ignoreAntMatchers
it?
public SecurityFilterChain securityFilterChain(
HttpSecurity http,
OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService,
CustomOAuth2SuccessHandler customOAuth2SuccessHandler
) throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.mvcMatchers(
...
"/account/logout"
).permitAll()
.mvcMatchers(
"/account/login",
...
).hasRole("ANONYMOUS")
...
)
.csrf()
.ignoringAntMatchers("/account/logout")
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
...
.and()
.formLogin().disable()
.logout(logout -> logout
.logoutUrl("/account/logout")
)
.oauth2Login(oAuth -> oAuth
.loginPage("/account/login")
.userInfoEndpoint(userInfo -> userInfo
.userService(oAuth2UserService))
.successHandler(customOAuth2SuccessHandler)
)
//i'm using jwt token
.addFilterBefore(
new JwtTokenFilter(userAccountService, jwtProperties),
BasicAuthenticationFilter.class)
...
}
SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
@PostMapping("/account/logout")
public String requestLogout(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
this.logoutHandler.logout(request, response, authentication);
return "redirect:/";
}
<form id="logout" action="/account/logout" method="post">
<button type="submit" class="btn text-success p-0">LogOut</button>
</form>
trace error log did not appear. server logs there's nothing.
Upvotes: 0
Views: 3651
Reputation: 72
The cause of this issue was the Stateless session setting. By default, Spring Security stores the expected CSRF token in the HttpSession by using HttpSessionCsrfTokenRepository
. So, the CSRF token could not be loaded.
I was able to persist the CsrfToken in a cookie using the CookieCsrfTokenRepository
.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// ...
.csrf((csrf) -> csrf
.csrfTokenRepository(new CookieCsrfTokenRepository())
);
return http.build();
}
}
In addition, after applying a stateless session, it was regenerated by the CsrfAuthenticationStrategy
, resulting in a token mismatch error. This issue was solved by placing the jwtFilter
before the ExceptionTranslationFilter
or after the SessionMnagmentationFilter
.
Upvotes: 0
Reputation: 21
As correctly mentioned, when using .ignoringAntMatchers("/account/logout")
you are disabling CSRF protection for that endpoint. The reason behind the 403 response could be that the CSRF token is not part of the POST request.
There are different ways to do this, but a common approach is to have the token in a hidden input field within your form. For example, if you are working with JSP, an easy way to do it is to access and render the CSRF token with Expression Language, by using ${_csrf.parameterName}
and ${_csrf.token}
.
An example:
<form action="/logout" method="post">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<input type="submit" value="Log out"/>
</form>
and Spring takes care of the rest. More info here:
Upvotes: 1