Spring WebClient set Bearer auth token in header
Asked Answered
K

4

17

Following scenario:

I have two Microservices A and B. Service A is a Bearer client that has an open api and receives requests from clients that have to be authorized by keycloak. Now I want to send an authorized Request from Service A to Service B, which is also a bearer client.

I thought about adding the functionality as a filter function during the webclient builder process like

@Bean
WebClient webClient() {
    return WebClient.builder()
            .filter(authHeader())
            .build();
}

private ExchangeFilterFunction authHeader(String token) {
    return (request, next) -> next.exchange(ClientRequest.from(request).headers((headers) -> {
        headers.setBearerAuth(token);
    }).build());
}

This is an example I found in another question. It seems to to be the right way to me but can I provide the "String token" parameter at that stage of configuration?

I'm just switching from RestTemplate to WebClient, so sorry I this is a dump question.

EDIT: I am able to set the header manually while building a new WebClient.

return WebClient.builder()
        .defaultHeader("Authorization", "Bearer "+ context.getTokenString())
        .build();

As I know from the RestTemplate, it can be used as a Singleton. There also exists a KeyCloakRestTemplate which injects the header automatically.

WebClient is immutable, so when I inject it, I can't just use it and add the header afterwards. In addition, I can't set this header on startup as I have to wait for a request to take the bearer header and pass it in. So I guess there is not other way than doing it this way?

Kroo answered 11/12, 2020 at 10:56 Comment(1)
It does not work for me if I set the bearer token as default header. I have to insert it as header when requesting. Any idea why?Micromillimeter
M
10

Or simply set it during the process of sending:

webClient.get()
    .uri(url)
    .headers(h -> h.setBearerAuth(token))
    .retrieve();
Mexico answered 9/2, 2022 at 8:38 Comment(0)
U
5

I ended up using an ExchangeFilterFunction filter in a similar situation. In my case, I have a Spring component which retrieves the token to use. If context in your context.getTokenString() example is a Spring bean, you should be able to do the same:

@Bean
WebClient webClient(SomeContext context) {
    return WebClient.builder()
            .filter((request, next) -> next.exchange(
                    withBearerAuth(request, context.getTokenValue())))
            .build();
}

private static ClientRequest withBearerAuth(ClientRequest request, 
                                            String token) {
    return ClientRequest.from(request)
            .header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
            .build();
}
Ulster answered 8/9, 2022 at 22:1 Comment(0)
X
0

Maybe this helps:

public class WebClientExample {
    public static void main(String[] args) {
        try {
            String bearerToken = "your_token_here"; // Replace with your actual token
            String uri = "your_api_endpoint_here"; // Replace with your actual URI

            WebClient webClient = WebClient.builder()
                    .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + bearerToken)
                    .build();

            String response = webClient.post()
                    .uri(uri)
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();

            System.out.println("Response: " + response);
        } catch (Exception e) {
            System.err.println("Error while sending request: " + e.getMessage());
        }
    }
}
Xanthene answered 5/6 at 13:27 Comment(0)
O
0

In order to just transfer the token (you can of course give it also other attributes), you could create a "basic" WebClient like this:

@Bean
public WebClient webClient() {
    return WebClient.builder()
            .build();
}

Then inject this webClient where you need it, and call the next service at e.g. localhost:8083 at request time this way:

ResponseEntity<String> response = webClient.get()
        .uri("http://localhost:8083/")
            .headers((headers) -> headers.add("authorization", "Bearer " + token))
            .retrieve().toEntity(String.class).block();

To retrieve the token at the second server, you could e.g. specify @AuthenticationPrincipal Jwt principal as parameter in the REST method or get it from the HttpServletRequest.

Organotherapy answered 5/6 at 17:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.