Describe the bug
Following the migration guide for reactive applications,
I configured a WebFlux application with http.csrf().csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()).csrfTokenRequestHandler(new XorServerCsrfTokenRequestAttributeHandler()::handle) and a WebFilter bean to "ensure the token is subscribed to",
but I can't find any CSRF cookie anywhere in my browser debugging tools (neither with XSRF-TOKEN "standard" name, nor with any other name: the only cookie is the session one).
To Reproduce With this very simple Boot app:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@EnableWebFluxSecurity
@Configuration
static class WebSecurityConf {
@Bean
SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http, ServerProperties serverProperties) {
http.oauth2Client();
http.authorizeExchange().pathMatchers("/login/**", "/oauth2/**").permitAll().anyExchange().authenticated();
http.oauth2Login();
http.logout().logoutUrl("/logout");
CookieServerCsrfTokenRepository tokenRepository = CookieServerCsrfTokenRepository.withHttpOnlyFalse();
XorServerCsrfTokenRequestAttributeHandler delegate = new XorServerCsrfTokenRequestAttributeHandler();
http.csrf().csrfTokenRepository(tokenRepository).csrfTokenRequestHandler(delegate::handle);
return http.build();
}
@Bean
WebFilter csrfCookieWebFilter() {
return (exchange, chain) -> {
Mono<CsrfToken> csrfToken = exchange.getAttributeOrDefault(CsrfToken.class.getName(), Mono.empty());
return csrfToken.doOnSuccess(token -> {
System.out.println(token);
}).then(chain.filter(exchange));
};
}
}
}
This prints null and I have no CSRF cookie.
Expected behavior I expect a CSRF cookie to be set
Sample https://github.com/ch4mpy/gh-12871
Comment From: Shaquu
Relates to #12869
Comment From: ch4mpy
Relates to #12869
@Shaquu not exactly: my problem is not related CSRF token validation, it is I don't have a cookie at all.
Comment From: lglauer
@ch4mpy
If you are using a single-page app (SPA) to connect to a backend protected by Spring Security along with CookieCsrfTokenRepository.withHttpOnlyFalse(), you may find that the CSRF token is no longer returned to your application as a cookie on the first request to the server.
https://docs.spring.io/spring-security/reference/5.8/migration/servlet/exploits.html#_i_am_using_a_single_page_application_with_cookiecsrftokenrepository
Comment From: ch4mpy
@lglauer I had missed that part, thank you for pointing me to it. This works for servlets but, unfortunately, the doc seems to be missing something for reactive applications.
I updated the issue with what is in the migration guide for reactive apps (and I'm trying to configure a spring-cloud-gateway instance).
Comment From: ch4mpy
Found my issue: I had accidentally imported org.springframework.security.web.csrf.CsrfToken instead of org.springframework.security.web.server.csrf.CsrfToken which caused the WebFilter to fail retrieving the CSRF token from exchange attributes.