I have a Spring Security OAuth2
with Keycloak
setup.
On Client
application side the artifacts look like this:
application.yml
server.port: 8182
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: myclient-ac
client-secret: 81e3fd9f-52ce-4549-8ea9-ae53e754da89
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8182/login/oauth2/code/myclient-ac
scope: openid
provider:
keycloak:
issuer-uri: http://localhost:8180/auth/realms/myrealm
#authorization-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/auth
#token-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/token
#user-info-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/userinfo
#jwk-set-uri: http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/certs
#user-name-attribute: preferred_username
SecurityConfig.java
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll()
.and()
.oauth2Login().disable()
.oauth2Client();
return http.build();
}
}
WebClientConfig.java
@Configuration
public class WebClientConfig {
@Bean
WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}
MyRestControllerClient.java
@RestController
public class MyRestControllerClient {
private static final Logger LOGGER = LoggerFactory.getLogger(MyRestControllerClient.class);
@Autowired
private WebClient webClient;
@GetMapping("/helloworld")
public String helloworld(@RegisteredOAuth2AuthorizedClient("keycloak") OAuth2AuthorizedClient authorizedClient) {
String body = webClient
.get()
.uri("http://localhost:8181/helloworld")
.attributes(oauth2AuthorizedClient(authorizedClient))
.retrieve()
.bodyToMono(String.class)
.block();
LOGGER.info(body);
return body;
}
@GetMapping("/oidc-principal")
public OidcUser getOidcUserPrincipal(@AuthenticationPrincipal OidcUser principal) {
return principal;
}
}
Accessing http://localhost:8182/helloworld results in being redirected to login page at Keycloak
. Providing username
and password
, I can successfully access my /helloworld
endpoint.
I want to access also the user information, according to 4.1. Accessing User Information
at https://www.baeldung.com/spring-security-openid-connect it can be done in the REST
controller via
@GetMapping("/oidc-principal")
public OidcUser getOidcUserPrincipal(@AuthenticationPrincipal OidcUser principal) {
return principal;
}
Adding this endpoint to my REST
controller, and accessing it after the /helloworld
endpoint, results in principal
being null
.
How to access the user information?
I changed this
@EnableWebSecurity
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll()
.and()
.oauth2Login().disable()
.oauth2Client();
return http.build();
}
}
to
.oauth2Login()
.and()
.oauth2Client();
now principal
is full of information.
But what's the difference now? OAuth2
worked with .oauth2Login().disable()
as expected, the behavior is the same, I get redirected to the login page at Keycloak, and the login happens with or without .disable()