Reputation: 2287
I am using Spring Boot Cloud OAuth client to connect with Salesforce restapi. However I am getting Session expired or invalid
error. Is there anyway to refresh token I was under the assumption that Spring Boot handles this automatically under the hood but seems like that is not the case. Here is the relevant code.
@Configuration
public class SalesforceConfiguration {
@Value("${salesforce.tokenUrl}")
private String tokenUrl;
@Value("${salesforce.clientId}")
private String clientId;
@Value("${salesforce.clientSecret}")
private String clientSecret;
@Value("${salesforce.username}")
private String username;
@Value("${salesforce.password}")
private String password;
@Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
resource.setAccessTokenUri(tokenUrl);
resource.setClientId(clientId);
resource.setClientSecret(clientSecret);
resource.setClientAuthenticationScheme(AuthenticationScheme.form);
resource.setUsername(username);
resource.setPassword(password);
return resource;
}
@Bean
public OAuth2RestOperations restTemplate() {
OAuth2RestTemplate operations = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
operations.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
operations.getMessageConverters().add(new StringHttpMessageConverter());
return operations;
}
}
and this is how I am using it in service.
@Component
public class QueryExecutor extends AbstractExecutor implements SalesforceExecutor {
private OAuth2RestOperations restOperations;
public QueryExecutor(OAuth2RestOperations restOperations) {
this.restOperations = restOperations;
}
@Override
public Response process(Request request) throws Exception {
JsonNode jsonNode = restOperations.getForObject(buildUrl(request), JsonNode.class);
return new Response<>(ResponseCode.SUCCESS_GET.getCode(), jsonNode, request.getResponseHandler());
}
private String buildUrl(Request request) {
return new StringBuilder().append(getServiceUrl(restOperations))
.append("/services/data/v41.0/query/?q=")
.append(request.getPayload().get("query"))
.toString();
}
}
Is there anyway to refresh token seamlessly using this approach if I get session expired error?
Upvotes: 0
Views: 2885
Reputation: 2287
Alright finally after days of debugging I think I found the solution of this issue. This is how I was able to resolve it. I am putting the solution here so that others can benefit from it.
@Component
public class QueryExecutor implements SalesforceExecutor {
private OAuth2RestOperations restOperations;
public QueryExecutor(OAuth2RestOperations restOperations) {
this.restOperations = restOperations;
}
@Override
public Response process(Request request) throws Exception {
try {
JsonNode jsonNode = restOperations.getForObject(buildUrl(request), JsonNode.class);
return new Response<>(ResponseCode.SUCCESS_GET.getCode(), jsonNode, request.getResponseHandler());
} catch (HttpClientErrorException | HttpServerErrorException e) {
if (HttpStatus.UNAUTHORIZED.value() == e.getStatusCode().value()) {
restOperations.getOAuth2ClientContext().setAccessToken(this.getRenewedToken(restOperations.getResource()));
}
// retry again with renewed token
}
}
private String buildUrl(Request request) {
return "someurl";
}
private OAuth2AccessToken getRenewedToken(OAuth2ProtectedResourceDetails resource) {
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest()));
return oAuth2RestTemplate.getOAuth2ClientContext().getAccessToken();
}
}
Thats it.
Upvotes: 0
Reputation: 1119
Using Spring Boot, you shouldn't need the entire SalesforceConfiguration
configuration class.
You can use the following dependencies:
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${look-for-the-latest}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
Add the configuration properties to your application.yml
:
security:
oauth2:
client:
username: the-username
password: the-password
client-id: the-client-id
client-secret: the-client-secret
grant-type: password,refresh_token
scope: read
access-token-uri: http://sales-force-domain/oauth/token
And then you can define your OAuth2RestTemplate
like this:
@Bean
public OAuth2RestTemplate oAuth2RestTemplate(final OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details);
}
To use it just do how you're already doing, inject the OAuth2RestTemplate
in the QueryExecutor
. The refresh token will be handled by Spring once you defined it as a grant-type
in the application.yml
.
In this repo, I've got a working version of this configuration, bear with me because it also demonstrates how to manually create this configuration.
Upvotes: 1