1. POM Dependencies
Make sure to include the required dependencies in your pom.xml
to use OAuth2 and Spring Batch.
xml
<dependencies>
<!-- Spring Security OAuth2 Client -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- Spring Security OAuth2 Core -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-core</artifactId>
</dependency>
<!-- Spring Boot Starter Batch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
2. OAuth2 Configuration
This configuration class handles the OAuth2 token retrieval using the client credentials flow.
java
@Configuration
public class OAuth2ClientConfig {
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
3. Spring Batch Configuration
The Spring Batch configuration integrates OAuth2 to make API calls with the JWT token in the Authorization header.
java
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private EntityManagerFactory entityManagerFactory;
@Autowired
private RestTemplate restTemplate;
@Autowired
private OAuth2AuthorizedClientManager authorizedClientManager;
@Value("${spring.security.oauth2.client.registration.my-client-registration-id}")
private String clientRegistrationId;
// JpaPagingItemReader to read ApiRetry entities with status = "NEW"
@Bean
public JpaPagingItemReader<ApiRetry> jpaReader() {
JpaPagingItemReader<ApiRetry> reader = new JpaPagingItemReader<>();
reader.setEntityManagerFactory(entityManagerFactory);
reader.setQueryString("SELECT a FROM ApiRetry a WHERE a.status = :status");
reader.setParameterValues(Collections.singletonMap("status", "NEW"));
reader.setPageSize(10); // Configure the page size
return reader;
}
// Processor to call the API and update the status
@Bean
public ItemProcessor<ApiRetry, ApiRetry> apiProcessor() {
return item -> {
// Get the OAuth2 access token
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId(clientRegistrationId)
.principal("batch_job")
.build();
OAuth2AuthorizedClient authorizedClient = this.authorizedClientManager.authorize(authorizeRequest);
String accessToken = authorizedClient.getAccessToken().getTokenValue();
// Set the Authorization header with the JWT token
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
HttpEntity<Void> requestEntity = new HttpEntity<>(headers);
// Example of handling different HTTP methods
ResponseEntity<String> response = null;
if ("GET".equalsIgnoreCase(item.getMethod())) {
response = restTemplate.exchange(item.getApi(), HttpMethod.GET, requestEntity, String.class);
} else if ("POST".equalsIgnoreCase(item.getMethod())) {
response = restTemplate.exchange(item.getApi(), HttpMethod.POST, requestEntity, String.class);
}
// Handle response logic as needed
// Here we simply set the status to "COMPLETED"
item.setStatus("COMPLETED");
return item;
};
}
// JpaItemWriter to write the updated ApiRetry entity back to the database
@Bean
public JpaItemWriter<ApiRetry> jpaWriter() {
JpaItemWriter<ApiRetry> writer = new JpaItemWriter<>();
writer.setEntityManagerFactory(entityManagerFactory);
return writer;
}
// Step configuration that ties the reader, processor, and writer together
@Bean
public Step processStep() {
return stepBuilderFactory.get("processStep")
.<ApiRetry, ApiRetry>chunk(10)
.reader(jpaReader())
.processor(apiProcessor())
.writer(jpaWriter())
.build();
}
// Job configuration that starts the processStep
@Bean
public Job job() {
return jobBuilderFactory.get("job")
.incrementer(new RunIdIncrementer())
.start(processStep())
.build();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
4. OAuth2 Client Registration
Add the OAuth2 client registration details in your application.yml
or application.properties
to configure the client credentials.
yaml
spring:
security:
oauth2:
client:
registration:
my-client-registration-id:
client-id: your-client-id
client-secret: your-client-secret
authorization-grant-type: client_credentials
scope: your-scope
provider:
your-provider-id:
token-uri: https://example.com/oauth/token
5. Explanation
- OAuth2AuthorizedClientManager: Manages the retrieval and caching of OAuth2 tokens.
- OAuth2AuthorizeRequest: Represents the request to authorize a client and retrieve the token.
- RestTemplate with JWT: The
RestTemplate
is configured to include the JWT token in the Authorization header when making API calls. - Client Credentials Flow: The OAuth2 configuration uses the client credentials grant type, which is suitable for machine-to-machine communication (like a batch job).
6. Run the Job
When you run the Spring Boot application, the batch job will:
- Obtain an OAuth2 token using the client credentials flow.
- Call the API with the token in the Authorization header.
- Update the database with the status as "COMPLETED."
This setup ensures your batch job can securely interact with APIs using OAuth2 authentication. You can modify this configuration to meet your specific API interaction needs.