-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Description
Describe the bug
I am using spring-boot-starter-parent 2.6.4. I need to integrate with Okta api with client credentials private_key_jwt. Okta's /v1/token url needs client_assertion_type of urn:ietf:params:oauth:client-assertion-type:jwt-bearer, grant type as client_credentials and authentication method as PRIVATE_KEY_JWT.
Expected behavior
I would like to retrieve access token via client_credentials private_key_jwt flow through Spring Boot WebClient in-memory solution.
To Reproduce
I have the below bean configurations. However, v1/token url never gets called. I think the issue with client_assertion_type urn:ietf:params:oauth:client-assertion-type:jwt-bearer along with clientAuthenticationMethod as PRIVATE_KEY_JWT for grant type as client_credentials.
@Bean
ReactiveClientRegistrationRepository clientRegistrations() {
ClientRegistration registration = ClientRegistration
.withRegistrationId("OktaExample")
.tokenUri("https://{oktaDomain}/oauth2/v1/token")
.clientId(clientId)
.clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT)
.scope(scope)
.authorizationGrantType(new AuthorizationGrantType("urn:ietf:params:oauth:client-assertion-type:jwt-bearer"))
.build();
return new InMemoryReactiveClientRegistrationRepository(registration);
}
@Bean
public ReactiveOAuth2AuthorizedClientService authorizedClientService(
ReactiveClientRegistrationRepository clientRegistrations) {
return new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrations);
}
@Bean
public ReactiveOAuth2AuthorizedClientManager authorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrations,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
return configureHttpProxy(
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(
clientRegistrations,
authorizedClientService
));
}
private AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager configureHttpProxy(AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
Function<ClientRegistration, JWK> jwkResolver = client -> {
// Assuming RSA key type
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
};
// set the webclient with proxy configuration in the ReactiveOAuth2AccessTokenResponseClient
WebClientReactiveClientCredentialsTokenResponseClient tokenResponseClient = new WebClientReactiveClientCredentialsTokenResponseClient();
tokenResponseClient.addParametersConverter(new NimbusJwtClientAuthenticationParametersConverter<>(jwkResolver));
tokenResponseClient.setWebClient(
WebClient.builder().build()
);
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider= ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials(clientCredentialsGrantBuilder ->
clientCredentialsGrantBuilder.accessTokenResponseClient(tokenResponseClient))
.build();
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
@Bean
WebClient webClient(ReactiveOAuth2AuthorizedClientManager authorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServerOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("OktaExample");
return WebClient.builder()
.filters(exchangeFilterFunctions -> {
exchangeFilterFunctions.add(oauth2Client);
})
.build();
}