My understanding is:

  • You need a POST request to call /actuator/startup because you actually empty the event buffer server-side
  • By default, (Webflux) Spring Security adds a CSRF token verification to every PUT, POST and DELETE HTTP call
  • In the case of the startup endpoint, no token has been previously delivered since the POST is the first call
  • In all cases, the chance is very low that the call comes from a browser anyway

I have to remove the CSRF check explicitly:

@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authorizeExchange()
                .matchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .matchers(ServerWebExchangeMatchers.anyExchange()).authenticated()
                .and().httpBasic()
                .and().formLogin()
                .and().logout()
                .and().csrf().requireCsrfProtectionMatcher(isNot(EndpointRequest.to(StartupEndpoint.class)));
        return http.build();
    }

    private ServerWebExchangeMatcher isNot(ServerWebExchangeMatcher matcher) {
        return new NegatedServerWebExchangeMatcher(matcher);
    }
}

I think it would improve the developer experience to have this out of the box.

Comment From: philwebb

Thanks for raising this issue. We discussed it today as a team and decided that we don't want to remove CSRF protection by default. We'd prefer that users are explicit about removing CSRF support (even though there's not a good alternative at the moment).

I've opened some new issues to help solve some of the problems you've highlighted:

  • Adding GET support to /actuator/startup will make the endpoint easier to use (#24666)
  • We can provide some better methods to make requireCsrfProtectionMatcher less verbose (#24667)
  • Longer-term, we can try to find a alternative to CSRF when using curl (#24668)

Feel free to subscribe to any of those issues or add comments to them if you have suggestions.

Comment From: nfrankel

Thanks for your feedback!

This was in the context of a demo, so I won't be subscribing to the issues you opened, but I thought that it was "common" enough to warrant opening an issue.

And yes, offering a GET endpoint is the easiest solution (but then, you'll probably have a purist who points that it has side-effects)

Comment From: philwebb

The GET version will leave the buffer intact and so won't have any side-effects.