Hello. Perhaps this is not a right place to ask this question, but after many experiments I wonder if it's even possible to implement this with spring WebClient / reactor Important note: I don't need asynchrony, I use WebClient just because RestTemplate is deprecated and seems to be less customizable. As I don't need asynchrony I use my webClient in a synchronous way:

buildMyWebClient("123").get().retrieve().toBodilessEntity().block()

I've read dozen of examples on stackoverflow of how to implement "renewing auth token" filter (including the one from official documentation https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client-filter) None of the examples works for me.

Long story short

WebClient buildMyWebClient(String someId) {
    return webClientBuilder
        .filter(authenticate(someId))
        .filter(renewTokenOn401())
        .build();
}

ExchangeFilterFunction authenticate(String someId) {
    return (request, next) -> {
        String authToken = authService.getAuthToken(someId);
        var requestWithBearerAuth = ClientRequest
            .from(request)
            .headers(h -> h.setBearerAuth(authToken))
            .build();
        return next.exchange(requestWithBearerAuth);
    };
}

ExchangeFilterFunction renewTokenOn401(String someId) {
    return (request, next) -> next
        .exchange(request)
        .flatMap(response -> {
            if (response.statusCode() == HttpStatus.UNAUTHORIZED) {
                return response
                    .releaseBody()
                    .then(Mono.just(1)) // I don't need this at all, but without this useless .then() the consequent .flatMap() will not be fired
                    .flatMap((i_dont_need_this_parameter) -> {
                        authService.invalidateCache();
                        return authenticate(someId).filter(request, next); // this authenticate function is declared above
                    });
            } else {
                return Mono.just(response);
            }
        });
}

Renewing token in my case is calling authService.invalidateCache() which just drops data in redis + authService.getAuthToken(someId) which will retrieve a token, put it in redis and attach to subsequent request

The problems is my renewTokenOn401 filters causes:

block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2

which is absolutely non intuitive for me. How does it know there are blocking operations inside my flatMap? System.out.println("hi") is also a blocking operation, does that mean I can't println in my filters? How that even can distinguish between "a line of code which is blocking" from "non blocking"? If I comment authService.invalidateCache() in my renewTokenOn401 function - the error will gone, but without it my renewTokenOn401 filter becomes useless.

Comment From: bclozel

Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.

RestTemplate is not deprecated, it's been merely declared "in maintenance mode" as we don't plan on evolving significantly its features/main contracts. Implementing interceptors is a perflectly valid use case supported by Framework.

Spring Security implements OAuth support for both clients. There are ways to wrap blocking calls and make them work in your reactive pipeline. I think you'll find better assistance on StackOverflow for that. Thanks!