9

We are using spring security oauth2 to obtain token using client credentials grant type. We are not using the application.properties file for specifying the client credentials, instead we are supplying them programmatically.

ClientRegistration clientRegistration = ClientRegistration
        .withRegistrationId("test")
        .clientId("testclientid")
        .clientSecret("testclientsecret")
        .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
        .tokenUri("http://test.tokenuri.com")
        .build();

ReactiveClientRegistrationRepository reactiveClientRegistrationRepository = new InMemoryReactiveClientRegistrationRepository(clientRegistration);
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
        new ServerOAuth2AuthorizedClientExchangeFilterFunction(
                reactiveClientRegistrationRepository,
                new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("test");

this.webClient = webClientFactory.getBuilder()
        .filter(oauth)
        .build();

The code is working fine, but we see a warning that UnAuthenticatedServerOAuth2AuthorizedClientRepository is deprecated. The api docs for UnAuthenticatedServerOAuth2AuthorizedClientRepository recommend to use AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager instead, but AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager does not implement the same interface as UnAuthenticatedServerOAuth2AuthorizedClientRepository. What is the recommendation on replacing the deprecated UnAuthenticatedServerOAuth2AuthorizedClientRepository in this case?

I found https://github.com/spring-projects/spring-security/issues/8016 but the issue does not give much detail.

hzpz
  • 7,536
  • 1
  • 38
  • 44
Ajeet Bansal
  • 91
  • 1
  • 2

2 Answers2

9

With the help of @Jokers answer, I managed to solve this problem in the following way. I put the credentials in appliction.properties and seperated the RegistrationRepository for that.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class MyClientRequestConfig {

    @Bean
    ReactiveClientRegistrationRepository getRegistration(
            @Value("${spring.security.oauth2.client.provider.myprovider.token-uri}") String token_uri,
            @Value("${spring.security.oauth2.client.registration.myprovider.client-id}") String client_id,
            @Value("${spring.security.oauth2.client.registration.myprovider.client-secret}") String client_secret
    ) {
        ClientRegistration registration = ClientRegistration
                .withRegistrationId("myprovider")
                .tokenUri(token_uri)
                .clientId(client_id)
                .clientSecret(client_secret)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
                .build();
        return new InMemoryReactiveClientRegistrationRepository(registration);
    }

    @Bean(name = "myprovider")
    WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
        InMemoryReactiveOAuth2AuthorizedClientService clientService = new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
        AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, clientService);
        ServerOAuth2AuthorizedClientExchangeFilterFunction oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
        oauth.setDefaultClientRegistrationId("myprovider");
        return WebClient.builder()
                .filter(oauth)
                .build();

    }
}
snaeil
  • 351
  • 2
  • 11
  • Will it also refresh the token in case it is expired ? or I have write logic for that explicitly ? – ZIA UR REHMAN May 26 '21 at 00:55
  • Unfortunately I can't test this at the moment. But it should be easy to test if you have control over your provider you want to communicate to: Set the token timeout very low and send requests before and after timeout. – snaeil Jun 15 '21 at 10:19
  • 1
    I think you need to write logic for refreshing the token – Joker Jul 24 '21 at 11:26
  • As Joker said, explicit logic is needed for refreshing – snaeil Jan 18 '23 at 09:22
6

Allthough kotlin code (conversion should be easy to java), we ended up with something like that:

val clientRegistryRepo = InMemoryReactiveClientRegistrationRepository(ClientRegistration
    .withRegistrationId("test")
    .tokenUri("http://test.tokenuri.com")
    .clientId("testClientId")
    .clientSecret("testclientsecret")
    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
    .build())
val clientService = InMemoryReactiveOAuth2AuthorizedClientService(clientRegistryRepo)
val authorizedClientManager =
    AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistryRepo, clientService)
val oauthFilter = ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
oauthFilter.setDefaultClientRegistrationId("test")
WebClient.builder()
        .filter(oauthFilter)
        .build()
Joker
  • 2,304
  • 25
  • 36