javaspringspring-bootspring-securityjwt

WebFluxSecurity does not add Authentication to SecurityContext


I have this strange issue with Spring Cloud Security with the reactive stack. I setup Spring Cloud Gateway and at the same time, I made it be a RsourceServer so all incoming requests will have JWT granted from Firebase in this case. Here are some snapshots from my configuration.

application.yml Set JWK and Issuer, to tell spring security how JWT's should be validated.

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com
          issuer-uri: https://securetoken.google.com/${project_name}

SecurityConfig

    @EnableWebFluxSecurity
    public class SecurityConfig {

      @Bean
      public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        // @formatter:off
        http
            .csrf().disable()
            .authorizeExchange()
            .pathMatchers("/public").permitAll()
            .anyExchange().authenticated().and()
            .oauth2ResourceServer()
            .jwt();
        return http.build();
        // @formatter:on
      }
    }

and finally the controller

TestController just for test purposes I created Controller to check if security context is set or not.

@RestController
@Slf4j
public class TestController {

  @GetMapping("/public")
  public String getPublic() {
    if (SecurityContextHolder.getContext().getAuthentication() != null) {
      throw new IllegalStateException("Public API should not have any AuthContext");
    }

    return "All shiny you got your PUBLIC data!";
  }

  @GetMapping("/private")
  public String getPrivate(@AuthenticationPrincipal Jwt jwt) {
    log.info(jwt.getTokenValue());    //in here jwt present as should be
    if (SecurityContextHolder.getContext().getAuthentication() == null) {
      throw new IllegalStateException("Oops.... Private API should have AuthContext");
    }

    return "All shiny you got your PRIVATE data!";
  }

}

So I am super frustrated and hope someone can help me out here. according to all Spring Security docs, I dug into it seems to me that I should have my security context saved when JWT is valid.

The main purpose is to be able to use ServletBearerExchangeFilterFunction Which tries to get Authentication and token out of it and pass it downstream to other services in WebClient. However, it is NULL.

Bearer Token Propagation here it is clearly written that SecurityContext should be valid at that point already.

Any suggestions would be appreciated a lot.


Solution

  • You have to use the ReactiveSecurityContextHolder and chain it to the response of your Rest controller.

    Your @RestController needs to return a Mono or Flux to work correctly in a reactive environment.

    In general, ReactiveSecurityContextHolder is only available within a reactive context, meaning it should not be blocked. To access the Authentication or Principal, you must chain it properly within the reactive flow to ensure it remains accessible. e.g.

    return ReactiveSecurityContextHolder.getContext()
        .map { securityContext -> securityContext.authentication }
        .map { authentication -> authentication.principal }