Get current user id from Keycloak

I’m running a java-based external webservice that needs to know the user id after the user calls its http endpoint.

Basically, there are 2 cases. The user might be logged in or not. My current vague idea to achieve this is:

1.) User is logged in:

  • User clicks on link to the webservice.
  • Webservice redirects to Keycloak
  • Keycloak calls the webservice back with the userid

2.) User is not logged in:

  • User clicks on link to the webservice
  • Webservice redirects to Keycloak
  • Keycloak performs login
  • Redirect back to webservice with userid

What would be a way to achieve something similar to this? Ideally, this should be done via http redirects without involving javascript.

This turned out to be more complecated than I thought. Here is what I ended up doing:

  • Use spring-boot-starter-security with spring-boot-starter-oauth2-client

Connect Keycloak:

spring:
  security:
    oauth2:
      client:
        registration:
          xxx-client:
            provider: keycloak
            client-id: ...
            client-secret: ...
            client-authentication-method: client_secret_basic
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          keycloak:
            issuer-uri: .../realms/<Realm>
            user-name-attribute: sub

And then protect the endpoint:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  http
    .authorizeRequests(authorizeRequests -> authorizeRequests
      .antMatchers("/payment/test").authenticated()
      .anyRequest().anonymous())
    .oauth2Client(Customizer.withDefaults())
    .oauth2Login(Customizer.withDefaults());
  return http.build();
}

This way the webservice will perform a couple of redirects to establish the user identity. In the end I can access the id this way:

@GetMapping("payment/test")
public String test(@AuthenticationPrincipal DefaultOAuth2User user) {
  return user.getName();
}

This requires 4 redirects just to establish the id. But at least it works.

If you think this is to complex, you might want to have a look into the OAuth2/OIDC protocol spec. It‘s all like designed, for good reasons. It‘ not just „login and give me an id“.

Possibly interesting for you:
If you set the scope of your client.registration…. to the value openid you‘ll get an OidcUser instead of an OAuth2User in your method as an authenticator principal. The OidcUser will give you more standard user profile information, as mentioned in the OIDC spec.