Describe the bug With cookie csrf enabled in spring security in Webflux, the XSRF-TOKEN cookie is only generated once. And doesn't change even after a POST

To Reproduce Using POSTMAN, when I hit the first GET, the XSRF-TOKEN cookie is generated. Then I put the token in the header of my next POST and run it In the response I see that XSRF-TOKEN is still the same

Expected behavior The expected behaviour should be the same as in the Servlet (blocking) version: The csrf token is regenerated on each request and override the value on the cookie

Sample sample project with csrf enabled

@Configuration
@EnableWebFluxSecurity
public class WebSecurity {


    @Bean
    public SecurityWebFilterChain securityWebFilterChainDatabase(ServerHttpSecurity http) {
        return http
                .csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
                .httpBasic()
                .and()
                .authorizeExchange()
                .anyExchange()
                .authenticated().and().build();
    }

    @Bean
    public WebFilter addCsrfToken() {
        // workaround as explained here: https://github.com/spring-projects/spring-security/issues/5766
        return (exchange, next) -> {
            Mono<CsrfToken> csrfToken = exchange.getAttribute(CsrfToken.class.getName());
            return csrfToken.doOnSuccess(token -> {})
                    .then(next.filter(exchange));
        };
    }
}

Comment From: sjohnr

Hi @hanouard, thanks for reaching out!

Expected behavior The expected behaviour should be the same as in the Servlet (blocking) version: The csrf token is regenerated on each request and override the value on the cookie

In a servlet application, the CSRF token is not actually regenerated on each request, but is regenerated once after a successful authentication (see CsrfAuthenticationStrategy) along with a new session id (see Session Fixation Protection).

If you are not providing the JSESSIONID cookie with your requests in Postman, I do believe it would appear as though the CSRF token is being regenerated upon each request. However, this is actually the result of a successful authentication attempt on each request, since there is no SecurityContext available at the start of each new request.

Having said that, the CSRF token is not automatically re-generated after a successful authentication in a Spring WebFlux application, as it is in a Spring MVC application. Is that what you are expecting, or does my explanation above change anything in your thought process?

Comment From: hanouard

Hello @sjohnr Thank you for your explanation.

In a servlet application, the CSRF token is not actually regenerated on each request, but is regenerated once after a successful authentication (see CsrfAuthenticationStrategy) along with a new session id (see Session Fixation Protection).

I'm using the csrf mecanism in stateless app with CookieServerCsrfTokenRepository. Maybe I've faced a side effect somehow on my servlet version, that makes the csrf token regenerate on each request, and took it for a standard behavior.

After some reading about the double submit cookie, I think that there's no point on regenerating them on a stateless app:

When a user visits (even before authenticating to prevent login CSRF), the site should generate a (cryptographically strong) pseudorandom value and set it as a cookie on the user's machine separate from the session identifier. The site then requires that every transaction request include this pseudorandom value as a hidden form value (or other request parameter/header). If both of them match at server side, the server accepts it as legitimate request and if they don't, it would reject the request.

Comment From: sjohnr

Hi @hanouard!

I'm using the csrf mecanism in stateless app with CookieServerCsrfTokenRepository.

A fully stateless application would not use a session (JSESSIONID, SESSIONID) or any credentials provided automatically by the browser (custom cookie, HTTP Basic). In your sample configuration, you are using HTTP Basic so you are correct to include CSRF protection.

Maybe I've faced a side effect somehow on my servlet version, that makes the csrf token regenerate on each request, and took it for a standard behavior.

It sounds like you may not be providing the JSESSIONID on subsequent requests.

After some reading about the double submit cookie, I think that there's no point on regenerating them on a stateless app:

Just to clarify, are you saying the behavior you're seeing is consistent with your understanding of how things should work? If so, shall we close this issue?

Comment From: hanouard

Hello @sjohnr

Just to clarify, are you saying the behavior you're seeing is consistent with your understanding of how things should work? If so, shall we close this issue?

yes :) and thanks again for your time!