Skip to content

Instantly share code, notes, and snippets.

@sandipchitale
Last active May 8, 2023 06:38
Show Gist options
  • Save sandipchitale/cfa2d6e212dd76113a2c7f819e1fd0f4 to your computer and use it in GitHub Desktop.
Save sandipchitale/cfa2d6e212dd76113a2c7f819e1fd0f4 to your computer and use it in GitHub Desktop.
Spring Security OAuth2 Client with Client Credentials #oauth2_client_with_client_credentials

Procedure:

Config:

  • Bean for ClientRegistration or somehow create the client
  • Wrap the ClientRegistration instance in a (in memory?) ClientRegistrationRepository
  • Wrap the ClientRegistrationRepository in a (in memory?) OAuth2AuthorizedClientService
  • Wrap the ClientRegistrationRepository and OAuth2AuthorizedClientService in a AuthorizedClientServiceOAuth2AuthorizedClientManager
    • Build OAuth2AuthorizedClientProvider for AuthorizationGrantType.CLIENT_CREDENTIALS grant type
    • Set OAuth2AuthorizedClientProvider as AuthorizedClientProvider

Usage:

  • Inject the AuthorizedClientServiceOAuth2AuthorizedClientManager
  • Build OAuth2AuthorizeRequest with clientRegistrationId and Principal
    • Call authorize with OAuth2AuthorizeRequest to obtain OAuth2AuthorizedClient
      • Use OAuth2AuthorizedClient to obtain access token
      • Use access token to call API using RestTemplate
        • Basically set Authorization: Brearer <access_token> header
import java.util.Arrays;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Profiles;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager;
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.web.client.RestTemplate;
import org.springframework.stereotype.Component;
@Component
@Profile("client")
public static class CLR implements CommandLineRunner, ApplicationContextAware {
// Inject the OAuth authorized client authorized client manager
// from the OAuthClientConfiguration class
@Autowired
private AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientServiceAndManager;
@Override
public void run(String... args) throws Exception {
if (this.authorizedClientServiceAndManager == null) {
System.out.println("No authorizedClientServiceAndManager");
return;
}
// Build an OAuth2 request for the Okta provider
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest.withClientRegistrationId("okta")
.principal("0oa9fkf9a744SMgHt5d7")
.build();
// Perform the actual authorization request using the authorized client service and authorized client
// manager. This is where the JWT is retrieved from the Okta servers.
OAuth2AuthorizedClient authorizedClient = this.authorizedClientServiceAndManager.authorize(authorizeRequest);
// Get the token from the authorized client object
OAuth2AccessToken accessToken = Objects.requireNonNull(authorizedClient).getAccessToken();
System.out.println("Issued: " + accessToken.getIssuedAt().toString() + ", Expires:"
+ accessToken.getExpiresAt().toString());
System.out.println("Scopes: " + accessToken.getScopes().toString());
System.out.println("Token: " + accessToken.getTokenValue());
// Add the JWT to the RestTemplate headers
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken.getTokenValue());
headers.add(HttpHeaders.ACCEPT, "application/json; okta-version=1.0.0");
HttpEntity<?> request = new HttpEntity<>(headers);
// Make the actual HTTP GET request
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
ResponseEntity<String> response = restTemplate.exchange(
"https://dev-76041835-admin.okta.com/idp/myaccount/emails",
HttpMethod.GET,
request,
String.class);
String result = response.getBody();
System.out.println("Reply = " + result);
}
}
package com.sandipchitale.oauth2.client.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.oauth2.client.*;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.ClientRegistrations;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
@Configuration
@Profile("client")
public class OAuthClientConfiguration {
// Create the Github client registration
@Bean
@Profile("okta")
ClientRegistration oktaClientRegistration() {
// Alternativeliy, use ClientRegirtsation.withRegistrationId("okta")
// to get the builder and then set the other properties
ClientRegistration clientRegistration =
ClientRegistrations.fromIssuerLocation("https://dev-76041835.okta.com/oauth2/default")
.registrationId("okta")
.clientName("CLIENT_NAME")
.clientId("CLIENT_ID")
.clientSecret("CLIENT_SECRET")
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.scope("okta.myAccount.email.read")
.build();
return clientRegistration;
}
// Create the client registration repository
@Bean
public ClientRegistrationRepository clientRegistrationRepository(ClientRegistration oktaClientRegistration) {
InMemoryClientRegistrationRepository inMemoryClientRegistrationRepository = new InMemoryClientRegistrationRepository(oktaClientRegistration);
return inMemoryClientRegistrationRepository;
}
// Create the authorized client service
@Bean
public OAuth2AuthorizedClientService auth2AuthorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {
InMemoryOAuth2AuthorizedClientService inMemoryOAuth2AuthorizedClientService = new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
return inMemoryOAuth2AuthorizedClientService;
}
// Create the authorized client manager and service manager using the
// beans created and configured above
@Bean
public AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientServiceAndManager (
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientService);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment