Hi,

Recently i tasked myself with bumping spring boot from 2.7.18 to 3.2.2 and I thought that it is over and it's working but it is partially true.

I have an issue where when I return Mono or Completable Future my response losses the security context and I don't have idea how to handle it ;/ I think that's related to my configuration or it's a bug

when I try to call my async endpoints from spring-mvc i get these logs and then 403:

10:51:15.471 DEBUG DefaultPooledConnectionProvider - [9892e210, L:/10.9.248.21:56812 - R:/10.9.27.29:12750] onStateChange(GET{uri=/logic, connection=PooledConnection{channel=[id: 0x9892e210, L:/10.9.248.21:56812 - R:/10.9.27.29:12750]}}, [disconnecting]) 10:51:15.471 DEBUG DefaultPooledConnectionProvider - [9892e210, L:/10.9.248.21:56812 - R:/10.9.27.29:12750] Releasing channel 10:51:15.472 DEBUG PooledConnectionProvider - [9892e210, L:/10.9.248.21:56812 - R:/10.9.27.29:12750] Channel cleaned, now: 0 active connections, 1 inactive connections and 0 pending acquire requests. 10:51:15.473 DEBUG FilterChainProxy - Securing GET /api/market-maker-data/logics?applicationName=mm_pancakeswap_flokibnb 10:51:15.473 DEBUG AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext 10:51:15.476 DEBUG Http403ForbiddenEntryPoint - Pre-authenticated entry point called. Rejecting access 10:51:15.477 DEBUG FilterChainProxy - Securing GET /?applicationName=mm_pancakeswap_flokibnb 10:51:15.477 DEBUG AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext 10:51:15.477 DEBUG Http403ForbiddenEntryPoint - Pre-authenticated entry point called. Rejecting access

my spring boot dependencies :

spring-boot-starter-web spring-boot-starter-web - it is used on some of my endpoints and according to the documentation it's working on spring-mvc basis. - worked on 2.7.18 spring-boot-starter-websocket spring-boot-starter-security

To Reproduce Having like this configuration:

@ResponseStatus(HttpStatus.OK)
@GetMapping(path = "/barka", produces = APPLICATION_JSON_VALUE)
@PreAuthorize(SecurityRuleSet.ALL_USERS)
@Operation(summary = SWAG_ALL_USERS + "Get logics from specified application")
public CompletableFuture<String> method() {
    return retrieverService.getBarka();
}
  @ResponseStatus(HttpStatus.OK)
@GetMapping(path = "/logics", produces = {APPLICATION_JSON_VALUE})
@PreAuthorize(SecurityRuleSet.ALL_USERS)
@Operation(summary = SWAG_ALL_USERS + "Get logics from specified application")
public Mono<List<LogicInfoMMResponseDTO>> getLogics(@NotBlank @RequestParam String applicationName) {
    return retrieverService.getLogicsForFront(MMFilterableCommand.builder()
            .applicationName(applicationName).build());
}

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true, mode = PROXY)
public class WebSecurityConfig {

    private final AbstractCookieManager abstractCookieManager;
    private final FilterChainHandler filterChainHandler;
    private final SpringJwtTokenProvider springJwtTokenProvider;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws  {
        http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .csrf(AbstractHttpConfigurer::disable)
                .cors(AbstractHttpConfigurer::disable)

                .authorizeHttpRequests(auth -> {
                    auth

                            .anyRequest().authenticated();
                })
                .formLogin(AbstractHttpConfigurer::disable)
                .logout(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .addFilterBefore(filterChainHandler, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new CookieJwtTokenFilter(abstractCookieManager), UsernamePasswordAuthenticationFilter.class);

        return http.build();

    }

    @Bean
    public WebSecurityCustomizer configure() {
        return web -> web.ignoring().requestMatchers("/api/login","/api/logout", "/api/refresh-token",
                "/v3/api-docs/**", "/swagger-ui.html", "/swagger-ui/**"
                , "/api/version", "/api/monitoring/log", "/api/jenkins-job-update"
                , "/ws/public/**"
        );
    }


    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http)
            throws  {
        return http.getSharedObject(AuthenticationManagerBuilder.class)
                .build();
    }
    @Bean
    @RequestScope
    public UserContext requestScopeRequestData() {
        return new UserContext(springJwtTokenProvider);
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("*"));
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }
}
````


**Expected behavior**
It should work as it was in version 5.7.11 of spring-security.


I hope that it is somewhat clear and if it's not - my apologies !
My first ever potential bug report on any of libraries...

Kind regards,
Bartek


**Comment From: marcusdacoregio**

Hi, @BartekO999. Can you share the implementation of `CookieJwtTokenFilter` or provide a minimal, reproducible sample?
I believe that you are not saving the `SecurityContext` anywhere and therefore, when the ASYNC dispatch handles the async request (see https://github.com/spring-projects/spring-security/issues/11962#issuecomment-1320346945), the context is not available.

**Comment From: BartekO999**

Hi @marcusdacoregio 
Sure thing ! 
here is the code :) 
It's a bit extendend due to my attempts to fix the issue but to no awail..

```java

@RequiredArgsConstructor
public class CookieJwtTokenFilter extends OncePerRequestFilter {

    private final AbstractCookieManager abstractCookieManager;

    @Override
    protected void doFilterInternal(@NotNull HttpServletRequest httpServletRequest, @NotNull HttpServletResponse httpServletResponse, FilterChain filterChain) throws Servlet, IO {
        String token = abstractCookieManager.resolveCookieToken(httpServletRequest);
        try {
            if (token != null && abstractCookieManager.validateToken(token)) {
               var authentication =  abstractCookieManager.getAuthentication(token);
                SecurityContext sc = SecurityContextHolder.getContext();
                sc.setAuthentication(authentication);
                HttpSession session = httpServletRequest.getSession(true);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                SecurityContextHolder.setContext(sc);
                session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);

            }
        } catch (MMGui ex) {
            SecurityContextHolder.clearContext();
            httpServletResponse.send(ex.getHttpStatus().value(), ex.getMessage());
            return;
        }
        catch ( ex) {
            SecurityContextHolder.clearContext();
            httpServletResponse.send(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
            return;
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

}

Comment From: marcusdacoregio

@BartekO999, you must save the SecurityContext so it is available in the ASYNC dispatch (see https://github.com/spring-projects/spring-security/issues/11962#issuecomment-1320346945). Something like:

private SecurityContextRepository repository = new RequestAttributeSecurityContextRepository();

// ...
var context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
this.repository.saveContext(context, request, response);
// ...

For more details, please read https://docs.spring.io/spring-security/reference/servlet/authentication/session-management.html.

I'm closing this since this questions is more suited to StackOverflow, we prefer to keep issues only for bugs and enhancements. If you think that this is a bug, please provide a minimal, reproducible sample.

Comment From: BartekO999

Thanks @marcusdacoregio for you help - I will try to work with the details that you provided :)

Comment From: ugurberkecan

@BartekO999 which one helped you to fix it ?