0

I'm having some trouble understanding how to customize an authentication request made using Oauth2 when applying a ServerOAuth2AuthorizedClientExchangeFilterFunction filter on a WebClient.Builder that is used as a base for all WebClient instances.

The system itself is working, and the request is generated according to Oauth2 specifications. However, my authentication service has some extra fields that need to be present in order for the authentication to work. That's the problem, so far I couldn't find any reasonable way of adding the field that I need or customizing the request itself.

The only wat I could find so far would be to implement a ReactiveOAuth2AuthorizedClientManager. But I'm quite resistant about doing that, since there is no generic implementation of that interface that I can extend, and all available implementations are final and can't be extended. Since my use case would be only to add a field to the request body, I hope there is a better way of achieving that.

Any help would be highly appreciated. Thanks for your time.

What I want to achieve

  • Add a field to the authentication Oauth2 request, managed by spring security

What's getting in the way

  • Couldn't find a way to customize adding custom fields to the authentication request. There is too much voodoo magic happening behind the curtain.

Configuration

@Configuration
public class WebClientConfig {

    @Bean("azure")
    public ReactiveClientRegistrationRepository getRegistration(
            @Value("${spring.security.oauth2.client.provider.azure.token-uri}")
            String tokenUri,
            @Value("${spring.security.oauth2.client.registration.azure.client-id}")
            String clientId,
            @Value("${spring.security.oauth2.client.registration.azure.client-secret}")
            String clientSecret,
            @Value("${spring.security.oauth2.client.registration.azure.authorization-grant-type}")
            String authorizationGrantType
    )
    {
        ClientRegistration registration = getClientRegistration(
                "azure",
                tokenUri,
                clientId,
                clientSecret,
                getAuthorizationGrantType(authorizationGrantType)
        );
        return new InMemoryReactiveClientRegistrationRepository(registration);
    }

    protected AuthorizationGrantType getAuthorizationGrantType(@Value("${spring.security.oauth2.client.registration.azure.authorization-grant-type}") String authorizationGrantType) {
        return new AuthorizationGrantType(authorizationGrantType);
    }

    protected ClientRegistration getClientRegistration(
            String registrationId,
            String tokenUri,
            String clientId,
            String clientSecret,
            AuthorizationGrantType authorizationGrantType
    ) {
        return ClientRegistration
                    .withRegistrationId(registrationId)
                    .tokenUri(tokenUri)
                    .clientId(clientId)
                    .clientSecret(clientSecret)
                    .authorizationGrantType(authorizationGrantType)
                    .build();
    }

    @Bean
    public ServerOAuth2AuthorizedClientExchangeFilterFunction  oauth2AuthenticationFilter(
            @Qualifier("azure") ReactiveClientRegistrationRepository clientRegistrations
    ) {
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                clientRegistrations,
                        new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
        oauth.setDefaultClientRegistrationId("azure");
        oauth.setDefaultOAuth2AuthorizedClient(true);
        return oauth;
    }

    @Bean("base")
    public WebClient.Builder webClientBaseBuilder()
    {
        return WebClient.builder();
    }

    @Bean
    @Primary
    public WebClient.Builder webClientBuilderWithFilters(
            @Qualifier("base") WebClient.Builder baseBuilder,
            ServerOAuth2AuthorizedClientExchangeFilterFunction  oauth2AuthenticationFilter
    ) {
        return baseBuilder
                .filter(oauth2AuthenticationFilter);
    }

    @Bean
    public WebClient webClient(
            @Value("${api.appId}") String appId,
            @Value("${api.url}") String url,
            WebClient.Builder builder
    ) {
        return builder
                .baseUrl(url)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader("Application-Id", appId)
                .build();
    }

}
Tin Megali
  • 771
  • 5
  • 25

1 Answers1

1

Refer to the spring security documentation, Assuming you are using client credentials grant

If you need to customize the pre-processing of the Token Request, you can provide DefaultClientCredentialsTokenResponseClient.setRequestEntityConverter() with a custom Converter<OAuth2ClientCredentialsGrantRequest, RequestEntity<?>>

https://docs.spring.io/spring-security/site/docs/current/reference/html5/#customizing-the-access-token-request-3

Kasun
  • 642
  • 1
  • 7
  • 16