I am trying to use an ApiClient generated by swagger-codegen-maven-plugin (Version 3.0.0), to consume an OAuth2 secured REST API from within my spring boot application. The auth server (keycloak) provides a JWT and refresh token, but I cannot figure out how to best handle tokens in my bean. At the moment my bean looks like this:
@Configuration
public class SomeApiClientConfiguration {
@Bean
public SomeApi someApi() {
return new SomeApi(apiClient());
}
@Bean
public ApiClient apiClient() {
ApiClient apiClient = new ApiClient();
OAuth oAuth = (OAuth) apiClient.getAuthentication("auth");
oAuth.setAccessToken("");
return apiClient;
}
}
Question is: What is the best approach for getting the token and handling the refresh token?
EDIT: In order to get the token I want to use client ID, username, and password. Grant type: Password Credentials.
Best,
Marc
I was able to solve this problem and want to share the solution for future reference:
This is my SomeApiClientConfiguration:
@Configuration
public class SomeApiClientConfiguration{
@Value("${app.api.url}")
private String apiURL;
@Bean
public SomeApi someApi(OAuth2RestTemplate restTemplate) {
return new SomeApi(apiClient(restTemplate));
}
@Bean
public ApiClient apiClient(OAuth2RestTemplate restTemplate) {
var apiClient = new ApiClient(restTemplate);
apiClient.setBasePath(apiURL);
return apiClient;
}
}
Additionally I needed a SomeApiOAuth2Config class, which look as follows:
@Configuration
@EnableOAuth2Client
public class SomeApiOAuth2Config {
@Value("${app.api.client-id}")
private String clientId;
@Value("${app.api.token-endpoint}")
private String accessTokenUri;
@Value("${app.api.name}")
private String username;
@Value("${app.api.password}")
private String password;
@Bean
public ClientHttpRequestFactory httpRequestFactory() {
return new HttpComponentsClientHttpRequestFactory(httpClient());
}
@Bean
public HttpClient httpClient() {
var connectionManager = new PoolingHttpClientConnectionManager();
var maxPoolSize = 1;
connectionManager.setMaxTotal(maxPoolSize);
// This client is for internal connections so only one route is expected
connectionManager.setDefaultMaxPerRoute(maxPoolSize);
return HttpClientBuilder.create().setConnectionManager(connectionManager).build();
}
@Bean
public OAuth2ProtectedResourceDetails oauth2ProtectedResourceDetails() {
var details = new ResourceOwnerPasswordResourceDetails();
var resourceId = "";
details.setId(resourceId);
details.setClientId(clientId);
var clientSecret = "";
details.setClientSecret(clientSecret);
details.setAccessTokenUri(accessTokenUri);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
return details;
}
@Bean
public AccessTokenProvider accessTokenProvider() {
var tokenProvider = new ResourceOwnerPasswordAccessTokenProvider();
tokenProvider.setRequestFactory(httpRequestFactory());
return new AccessTokenProviderChain(
Collections.<AccessTokenProvider>singletonList(tokenProvider)
);
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public OAuth2RestTemplate restTemplate(@Qualifier("oauth2ClientContext") OAuth2ClientContext oauth2ClientContext) {
var template = new OAuth2RestTemplate(oauth2ProtectedResourceDetails(), oauth2ClientContext);
template.setRequestFactory(httpRequestFactory());
template.setAccessTokenProvider(accessTokenProvider());
template.getOAuth2ClientContext().getAccessTokenRequest().set("username", username);
template.getOAuth2ClientContext().getAccessTokenRequest().set("password", password);
return template;
}
}