-
-
Save monospacesoftware/07cfd9603442830d370024414a53f374 to your computer and use it in GitHub Desktop.
spring: | |
security: | |
oauth2: | |
client: | |
registration: | |
salesforce: | |
authorization-grant-type: password | |
client-authentication-method: post | |
client-id: <clientId> | |
client-secret: <clientSecret> | |
provider: salesforce | |
provider: | |
salesforce: | |
token-uri: https://foo.my.salesforce.com/services/oauth2/token | |
foo: | |
salesforce: | |
api-url: https://foo.my.salesforce.com/services/data/v49.0/sobjects/ | |
api-user-name: <username> | |
api-password: <password> |
package com.foo; | |
@Slf4j | |
@Service | |
public class SalesForceClient { | |
private final WebClient webClient; | |
public SalesForceService(@Qualifier("salesForceWebClient") WebClient webClient) { | |
this.webClient = webClient; | |
} | |
public String createCase(SalesForceCase salesForceCase) { | |
SalesForceResponse response = webClient.post() | |
.uri("/Case") | |
.contentType(MediaType.APPLICATION_JSON) | |
.body(BodyInserters.fromValue(salesForceCase)) | |
.retrieve() | |
.bodyToMono(SalesForceResponse.class) | |
.onErrorMap(e -> new SalesForceException("Error communicating with SalesForce API: " + e.getMessage(), e)) | |
.block(); | |
if (response == null) | |
throw new SalesForceException("No response from SalesForce API"); | |
if (!response.isSuccess()) | |
throw new SalesForceException("SalesForce API returned an error: " + Optional.ofNullable(response.getErrors()).map(List::toString).orElse("[]")); | |
return response.getId(); | |
} |
package com.foo.config; | |
import lombok.Getter; | |
import lombok.Setter; | |
import org.springframework.beans.factory.annotation.Qualifier; | |
import org.springframework.boot.context.properties.ConfigurationProperties; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.security.oauth2.client.*; | |
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; | |
import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction; | |
import org.springframework.web.reactive.function.client.WebClient; | |
import java.util.HashMap; | |
import java.util.Map; | |
@Getter | |
@Setter | |
@Configuration | |
@ConfigurationProperties(prefix = "foo.salesforce") | |
public class SalesForceConfig { | |
private String apiUrl; | |
private String apiUsername; | |
private String apiPassword; | |
@Bean | |
public OAuth2AuthorizedClientManager salesForceAuthorizedClientManager(ClientRegistrationRepository clientRegistrationRepository, | |
OAuth2AuthorizedClientService authorizedClientService) { | |
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() | |
.password() | |
.build(); | |
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = | |
new AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService); | |
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); | |
Map<String, Object> passwordAttributes = new HashMap<>(); | |
passwordAttributes.put(OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, getApiUsername()); | |
passwordAttributes.put(OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, getApiPassword()); | |
authorizedClientManager.setContextAttributesMapper(request -> passwordAttributes); | |
return authorizedClientManager; | |
} | |
@Bean | |
public WebClient salesForceWebClient(@Qualifier("salesForceAuthorizedClientManager") OAuth2AuthorizedClientManager authorizedClientManager) { | |
ServletOAuth2AuthorizedClientExchangeFilterFunction oAuth2Filer = new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager); | |
oAuth2Filer.setDefaultClientRegistrationId("salesforce"); | |
return WebClient.builder() | |
.filter(oAuth2Filer) | |
.baseUrl(getApiUrl()) | |
.build(); | |
} | |
} |
Just in case someone is looking for a reactive way 🙂
@Bean
@Qualifier(CLIENT_NAME)
ReactiveOAuth2AuthorizedClientManager authorizedClientManager(ReactiveClientRegistrationRepository clientRegistrationRepository,
ReactiveOAuth2AuthorizedClientService authorizedClientService) {
final ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider = ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.password()
.build();
final AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
authorizedClientManager.setContextAttributesMapper(request -> Mono.just(Map.of(
OAuth2AuthorizationContext.USERNAME_ATTRIBUTE_NAME, getUsername(),
OAuth2AuthorizationContext.PASSWORD_ATTRIBUTE_NAME, getPassword()
)));
return authorizedClientManager;
}
@Bean
@Qualifier(CLIENT_NAME)
WebClient webClient(@Qualifier(CLIENT_NAME) ReactiveOAuth2AuthorizedClientManager clientManager) {
final ServerOAuth2AuthorizedClientExchangeFilterFunction filter =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientManager);
filter.setDefaultClientRegistrationId(CLIENT_NAME);
return WebClient.builder()
.filter(filter)
.baseUrl(getBaseUrl())
.build();
}
@shone1991 This is probably the solution for your case 😬
I'm still getting org.springframework.security.oauth2.core.OAuth2AuthorizationException: [invalid_client_id] client identifier invalid
even if I use the same credentials as in Postman.
@pabbott-ANet Did you figure out how to solve that?
I'm still getting org.springframework.security.oauth2.core.OAuth2AuthorizationException: [invalid_client_id] client identifier invalid even if I use the same credentials as in Postman. @pabbott-ANet Did you figure out how to solve that?
Check authorization-grant-type
and client-authentication-method
in your provider configuration, if you're not using a predefined one.
@monospacesoftware thanks for sharing, one thing to notice though, since spring security 5.5 the values for client-authentication-method
changed, so instead of post
we need to replace it by client_secret_post
. I just ran into this issue updating spring boot, here we can see the commit and post
value was removed here for version 6.0.0
@larsf96 @maksymgendin check this out.
@monospacesoftware thanks for sharing, one thing to notice though, since spring security 5.5 the values for
client-authentication-method
changed, so instead ofpost
we need to replace it byclient_secret_post
. I just ran into this issue updating spring boot, here we can see the commit andpost
value was removed here for version 6.0.0@larsf96 @maksymgendin check this out.
Yeah, you're right, the values have changed. Thanks for notifying.
The "Login to OAuth" is coming because the service you created is also getting protected by OAUTH.
Refer to post: https://fullstackdeveloper.guru/2022/03/17/how-to-invoke-oauth2-protected-microservice-using-webclient-in-spring-boot/
Above states to use WebSecurityConfigurerAdapter to address this issue. However this is now deprecated. So can use SecurityFilterChain instead
https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter